<?php
/**
 * Detects the visitor's IP address and checks whether it exposes a
 * reachable HTTP/HTTPS server, then records it in servers.txt.
 *
 * Checked targets, per visitor IP:
 *   - http://IP          (default port 80,  no explicit port)
 *   - https://IP         (default port 443, no explicit port)
 *   - http://IP:8080
 *   - http://IP:8765
 *
 * If any of those responds like an HTTP(S) server, the plain IP is
 * appended to servers.txt (one entry per line), unless it's already there.
 */

error_reporting(E_ALL & ~E_DEPRECATED & ~E_NOTICE);

define('SERVERS_TXT', __DIR__ . '/servers.txt');
define('CONNECT_TIMEOUT', 3); // seconds

/**
 * Resolves the requesting client's IP address.
 * Falls back through common proxy headers, but REMOTE_ADDR is the only
 * value that can't be spoofed by the client itself.
 */
function get_client_ip() {
    $candidates = array('HTTP_CLIENT_IP', 'HTTP_X_FORWARDED_FOR', 'REMOTE_ADDR');

    foreach ($candidates as $key) {
        if (!empty($_SERVER[$key])) {
            $value = $_SERVER[$key];

            // X-Forwarded-For may contain a comma-separated chain; take the first IP.
            if (strpos($value, ',') !== false) {
                $parts = explode(',', $value);
                $value = trim($parts[0]);
            }

            if (filter_var($value, FILTER_VALIDATE_IP)) {
                return $value;
            }
        }
    }

    return isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '';
}

/**
 * Checks whether a TCP port is open and accepting connections.
 */
function is_port_open($host, $port, $timeout) {
    $errno = 0;
    $errstr = '';
    $conn = @fsockopen($host, $port, $errno, $errstr, $timeout);

    if ($conn) {
        fclose($conn);
        return true;
    }

    return false;
}

/**
 * Checks whether a URL responds with valid HTTP(S) headers.
 */
function is_http_server($url, $timeout) {
    $context = stream_context_create(array(
        'http' => array(
            'method'        => 'HEAD',
            'timeout'       => $timeout,
            'ignore_errors' => true,
        ),
        'https' => array(
            'method'        => 'HEAD',
            'timeout'       => $timeout,
            'ignore_errors' => true,
        ),
        'ssl' => array(
            'verify_peer'      => false,
            'verify_peer_name' => false,
        ),
    ));

    $headers = @get_headers($url, 0, $context);

    if ($headers === false || !isset($headers[0])) {
        return false;
    }

    return (bool) preg_match('/^HTTP\/\d\.\d\s+\d{3}/', $headers[0]);
}

/**
 * Builds the list of targets to probe for a given IP:
 *   - default HTTP  (no explicit port)
 *   - default HTTPS (no explicit port)
 *   - explicit port 8080
 *   - explicit port 8765
 */
function build_targets($ip) {
    return array(
        array('url' => 'http://' . $ip,           'port' => 80),
        array('url' => 'https://' . $ip,          'port' => 443),
        array('url' => 'http://' . $ip . ':8080',  'port' => 8080),
        array('url' => 'http://' . $ip . ':8765',  'port' => 8765),
    );
}

/**
 * Determines whether the given IP exposes at least one reachable
 * HTTP/HTTPS server across the default ports and 8080 / 8765.
 */
function has_online_server($ip) {
    foreach (build_targets($ip) as $target) {
        if (!is_port_open($ip, $target['port'], CONNECT_TIMEOUT)) {
            continue;
        }

        if (is_http_server($target['url'], CONNECT_TIMEOUT)) {
            return true;
        }
    }

    return false;
}

/**
 * Returns true if $ip is already present as a line in servers.txt.
 */
function ip_already_listed($ip) {
    if (!file_exists(SERVERS_TXT)) {
        return false;
    }

    $lines = file(SERVERS_TXT, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);

    foreach ($lines as $line) {
        if (trim($line) === $ip) {
            return true;
        }
    }

    return false;
}

/**
 * Appends $ip to servers.txt if it isn't already listed.
 */
function add_ip_to_servers($ip) {
    if (ip_already_listed($ip)) {
        return false;
    }

    file_put_contents(SERVERS_TXT, $ip . "\n", FILE_APPEND | LOCK_EX);
    return true;
}

// ----------------------------------------------------
// Main
// ----------------------------------------------------
$client_ip = get_client_ip();

if ($client_ip !== '' && filter_var($client_ip, FILTER_VALIDATE_IP)) {
    if (has_online_server($client_ip)) {
        add_ip_to_servers($client_ip);
    }
}

?>

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Links index — current style</title>
<style>
  :root {
    --bg: #ffffff;
    --text: #333333;
    --muted: #777777;
    --muted-2: #555555;
    --border: #cccccc;
    --link: #0645ad;
    --link-hover-bg: #dbe6ff;
    --chip-bg: #f0f4ff;
    --panel-bg: #ffffff;
  }
  @media (prefers-color-scheme: dark) {
    :root:not([data-theme="light"]) {
      --bg: #14161a;
      --text: #e8e8e8;
      --muted: #9a9a9a;
      --muted-2: #b3b3b3;
      --border: #3a3d42;
      --link: #8ab4ff;
      --link-hover-bg: #24304a;
      --chip-bg: #1d2436;
      --panel-bg: #1b1d22;
    }
  }
  :root[data-theme="dark"] {
    --bg: #14161a;
    --text: #e8e8e8;
    --muted: #9a9a9a;
    --muted-2: #b3b3b3;
    --border: #3a3d42;
    --link: #8ab4ff;
    --link-hover-bg: #24304a;
    --chip-bg: #1d2436;
    --panel-bg: #1b1d22;
  }
  * { box-sizing: border-box; }
  body {
    font-family: Arial, sans-serif;
    margin: 40px;
    max-width: 720px;
    margin-left: auto;
    margin-right: auto;
    background: var(--bg);
    color: var(--text);
  }
  h1 { color: var(--text); }
  h2 { color: var(--text); margin-top: 40px; }

  /* Header: title on the left, minimalist links on the right */
  .site-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 8px 24px;
  }
  .site-header h1 { margin: 0.67em 0; }
  .top-nav { display: flex; gap: 20px; font-size: 14px; }
  .top-nav a {
    color: var(--muted-2);
    text-decoration: none;
    padding: 2px 0;
    border-bottom: 1px solid transparent;
  }
  .top-nav a:hover { color: var(--link); border-bottom-color: var(--link); }
  .top-nav a:focus-visible,
  .page-list a:focus-visible { outline: 2px solid var(--link); outline-offset: 3px; border-radius: 2px; }

  .search-box { position: relative; margin-top: 12px; }
  .search-row { display: flex; gap: 8px; }
  #search-input {
    flex: 1; min-width: 0; box-sizing: border-box; padding: 10px 12px;
    font-size: 16px; border: 1px solid var(--border); border-radius: 6px;
    background: var(--panel-bg); color: var(--text);
  }
  #search-go {
    padding: 10px 18px; font-size: 15px; background: #0645ad; color: #fff;
    border: none; border-radius: 6px; cursor: pointer; white-space: nowrap;
  }
  #search-go:hover { background: #033a8c; }
  #suggestions {
    display: none; position: absolute; top: 100%; left: 0; right: 0;
    background: var(--panel-bg); border: 1px solid var(--border); border-top: none;
    border-radius: 0 0 6px 6px; max-height: 260px; overflow-y: auto; z-index: 10;
  }
  .suggestion-item { padding: 8px 12px; cursor: pointer; }
  .suggestion-item:hover { background: var(--link-hover-bg); }
  .suggestion-empty { padding: 8px 12px; color: var(--muted); }
  #top-words { display: flex; flex-wrap: wrap; gap: 8px; }
  .word-item {
    display: inline-block; padding: 6px 12px; background: var(--chip-bg);
    color: var(--link); text-decoration: none; border-radius: 16px; font-size: 14px;
  }
  .word-item:hover { background: var(--link-hover-bg); }

  /* About section */
  #about p { line-height: 1.6; margin: 12px 0 0; }
  .page-list { list-style: none; margin: 24px 0 0; padding: 0; }
  .page-list li {
    display: flex;
    align-items: baseline;
    gap: 16px;
    padding: 10px 0;
    border-top: 1px solid var(--border);
  }
  .page-list li:last-child { border-bottom: 1px solid var(--border); }
  .page-list a {
    flex: 0 0 96px;
    color: var(--link);
    text-decoration: none;
    font-size: 15px;
  }
  .page-list a:hover { text-decoration: underline; }
  .page-list span { color: var(--muted); font-size: 14px; }

  .note { color: var(--muted); font-size: 13px; margin-top: 32px; }
</style>
</head>
<body>
<header class="site-header">
  <h1>Meento <br><span style="font-size:10px;">Compatible with Java 8 - PHP 7.x</span></h1>

  <nav class="top-nav" aria-label="Main">
    <a href="others/php/upload.php">upload</a>
    <a href="others/json/index.html">link</a>
    <a href="others/php/videos/index.php">videos</a>
    <a href="others/java/tools/tools.html">tools</a>
  </nav>
</header>
<div class="search-box">
  <div class="search-row">
    <input type="text" id="search-input" placeholder="Search or type an exact word..." autocomplete="off">
    <button type="button" id="search-go">Open</button>
  </div>
  <div id="suggestions"></div>
</div>
<div id="top-words"></div>

<br><br>
<a href="guide.html">Open quick guide</a>
<br><br>

<section id="about">
  <ul class="page-list">
    <li><a href="others/php/upload.php">Upload</a><span>Upload  files</span></li>
    <li><a href="others/json/index.html">Links</a><span>Add informations and metadata</span></li>
    <li><a href="MeshareDesktop.java">Search</a><span>Find files and links</span></li>
    <li><a href="Meshare.java">Browser</a><span>Search files and links</span></li>
    <li><a href="others/java/tools/LinkProcessor.java">Processor</a><span>Convert "links.txt" to a static webpage</span></li>
    <li><a href="CrawlerGUI.java">Crawler</a><span>Find links in the web</span></li>
    <li><a href="others/java/tools/MeshareVerify.java">Integrity</a><span>Check file integrity in each server</span></li>
    <li><a href="others/java/tools/MeshareRank.java">Rank</a><span>The most shared files</span></li>
    <li><a href="others/java/tools/MeshareSync.java">Sync</a><span>Sync rank file</span></li>
    <li><a href="others/java/tools/MesharePoints.java">Points</a><span>Send and receive points</span></li>
    <li><a href="others/java/crypto/README_MesharePay.md">Crypto</a><span>Prototypes and tests</span></li>
    <li><a href="others/php/index.php">Indexer</a><span>MySQL for search and add</span></li>    
    <li><a href="others/php/videos/index.php">Videos</a><span>Simple video upload</span></li>  
    <li><a href="others/php/gallery/index.php">Gallery</a><span>Create a gallery</span></li>  

  </ul>
</section>

<p class="note">MIT License</p>
<script>
  var wordsData = ["test", "meento"];

  function wordPageUrl(word) {
    return "html_pages/" + word + ".html";
  }

  function buildWordLink(word) {
    var a = document.createElement("a");
    a.href = wordPageUrl(word);
    a.className = "word-item";
    a.textContent = word;
    return a;
  }

  function renderTopWords() {
    var container = document.getElementById("top-words");
    wordsData.forEach(function (word) {
      container.appendChild(buildWordLink(word));
    });
  }

  function initSearch() {
    var input = document.getElementById("search-input");
    var suggestions = document.getElementById("suggestions");
    var goButton = document.getElementById("search-go");

    function openTypedWord() {
      var word = input.value.trim().toLowerCase();
      if (!word) return;
      suggestions.style.display = "none";
      window.location.href = wordPageUrl(word);
    }

    function updateSuggestions() {
      var query = input.value.trim().toLowerCase();
      suggestions.innerHTML = "";
      if (!query) {
        suggestions.style.display = "none";
        return;
      }
      var matches = wordsData.filter(function (word) {
        return word.indexOf(query) !== -1;
      }).slice(0, 10);

      if (matches.length === 0) {
        var empty = document.createElement("div");
        empty.className = "suggestion-empty";
        empty.textContent = "No matching words in the starter list - click Open to try that exact page anyway";
        suggestions.appendChild(empty);
        suggestions.style.display = "block";
        return;
      }

      matches.forEach(function (word) {
        var div = document.createElement("div");
        div.className = "suggestion-item";
        div.textContent = word;
        div.addEventListener("click", function () {
          window.location.href = wordPageUrl(word);
        });
        suggestions.appendChild(div);
      });
      suggestions.style.display = "block";
    }

    input.addEventListener("input", updateSuggestions);
    input.addEventListener("focus", updateSuggestions);

    input.addEventListener("keydown", function (e) {
      if (e.key === "Enter") {
        var first = suggestions.querySelector(".suggestion-item");
        if (first) {
          first.click();
        } else {
          openTypedWord();
        }
      } else if (e.key === "Escape") {
        suggestions.style.display = "none";
      }
    });

    goButton.addEventListener("click", openTypedWord);

    document.addEventListener("click", function (e) {
      if (e.target !== input && e.target !== goButton && e.target.parentNode !== suggestions) {
        suggestions.style.display = "none";
      }
    });
  }

  document.addEventListener("DOMContentLoaded", function () {
    renderTopWords();
    initSearch();
  });
</script>
</body>
</html>