Add 'index.php'
This commit is contained in:
248
index.php
Normal file
248
index.php
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
<?php
|
||||||
|
// Simple URL shortener in a single PHP file
|
||||||
|
// by bagaag.com
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
$last_file = 'last.txt'; // file to store the last incremented key
|
||||||
|
$urls_file = 'urls.txt'; // file to store the URLs with their keys
|
||||||
|
$charset = 'acr8mqbs7di4tuh6e9fjv2gwx0nlk5poy1z3'; // unique set of characters for generating keys
|
||||||
|
$max_url_length = 100; // urls longer than this are considered nefarious
|
||||||
|
$allowed_domains = []; // list of allowed domains for URL shortening
|
||||||
|
$password = 'change me!'; // password to shorten a URL, leave empty to disable password protection
|
||||||
|
$enable_test = false; // enable the test function to output a series of incremented keys
|
||||||
|
|
||||||
|
// Returns the contents of $last_file, or empty string if the file does not exist
|
||||||
|
function get_last() {
|
||||||
|
global $last_file;
|
||||||
|
if (file_exists($last_file)) {
|
||||||
|
return trim(file_get_contents($last_file));
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// Writes to $last_file
|
||||||
|
function set_last($s) {
|
||||||
|
global $last_file;
|
||||||
|
file_put_contents($last_file, $s);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Provides the next key by incrementing the previous key.
|
||||||
|
// Start with empty string and then feed the return value
|
||||||
|
// back into this function to get the next key, and repeat.
|
||||||
|
function increment_string($s) {
|
||||||
|
global $charset;
|
||||||
|
// convert the charset to an array of characters
|
||||||
|
$chars = str_to_chars($charset);
|
||||||
|
// if the string is empty, return the first character
|
||||||
|
if ($s === '') {
|
||||||
|
return $chars[0];
|
||||||
|
}
|
||||||
|
// convert the input string to an array of characters
|
||||||
|
$string = str_to_chars($s);
|
||||||
|
// iterate over the input string characters from end to beginning
|
||||||
|
for ($index = count($string) - 1; $index >= 0; $index--) {
|
||||||
|
// find and validate the position of the character in the charset
|
||||||
|
$char = $string[$index];
|
||||||
|
$pos = array_search($char, $chars);
|
||||||
|
if ($pos === false) {
|
||||||
|
return "Character not in set: $char";
|
||||||
|
}
|
||||||
|
// if the character is not the last in the charset, increment it and break
|
||||||
|
if ($pos < count($chars) - 1) {
|
||||||
|
$string[$index] = $chars[$pos + 1];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// character is the last in the charset; wrap around to the first character
|
||||||
|
$string[$index] = $chars[0];
|
||||||
|
// if we are at the beginning of the string, prepend the first character and break
|
||||||
|
if ($index === 0) {
|
||||||
|
array_unshift($string, $chars[0]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return join('', $string);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Splits a string into an array of characters
|
||||||
|
function str_to_chars($str, $l = 0) {
|
||||||
|
if ($l > 0) {
|
||||||
|
$ret = array();
|
||||||
|
$len = mb_strlen($str, "UTF-8");
|
||||||
|
for ($i = 0; $i < $len; $i += $l) {
|
||||||
|
$ret[] = mb_substr($str, $i, $l, "UTF-8");
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
return preg_split("//u", $str, -1, PREG_SPLIT_NO_EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reads the last key, increments it, saves it, and returns it
|
||||||
|
function next_key() {
|
||||||
|
$last = get_last();
|
||||||
|
$next = increment_string($last);
|
||||||
|
set_last($next);
|
||||||
|
return $next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a URL to urls.txt and returns the generated key
|
||||||
|
function add_url($url) {
|
||||||
|
global $urls_file;
|
||||||
|
$key = next_key();
|
||||||
|
// append the key and url to urls.txt
|
||||||
|
file_put_contents($urls_file, $key . ' ' . $url . "\n", FILE_APPEND);
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Looks up a key in urls.txt and returns the corresponding URL, or null if not found
|
||||||
|
function get_url($key) {
|
||||||
|
global $urls_file;
|
||||||
|
$lines = file($urls_file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
|
||||||
|
foreach ($lines as $line) {
|
||||||
|
list($k, $url) = explode(' ', $line, 2);
|
||||||
|
if ($k === $key) {
|
||||||
|
return $url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test function to print a series of incremented keys
|
||||||
|
// Usage: output_keys('', 100);
|
||||||
|
function output_keys($key, $count) {
|
||||||
|
header('Content-Type: text/plain');
|
||||||
|
for ($i = 0; $i < $count; $i++) {
|
||||||
|
$key = increment_string($key);
|
||||||
|
// set content type to plain text
|
||||||
|
print($key . "\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get input either from a GET or POST request
|
||||||
|
function get_input($name) {
|
||||||
|
if (isset($_POST[$name])) {
|
||||||
|
return $_POST[$name];
|
||||||
|
} elseif (isset($_GET[$name])) {
|
||||||
|
return $_GET[$name];
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test if a host is in the allowed domains list
|
||||||
|
function test_host($host) {
|
||||||
|
global $allowed_domains;
|
||||||
|
if (empty($allowed_domains)) {
|
||||||
|
return true; // if the list is empty, allow all domains
|
||||||
|
}
|
||||||
|
return in_array($host, $allowed_domains);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* HTTP Request Handling */
|
||||||
|
|
||||||
|
// read input parameters
|
||||||
|
$url = get_input('url');
|
||||||
|
$input_password = get_input('password');
|
||||||
|
$key = get_input('key');
|
||||||
|
$test_start = get_input('test_start');
|
||||||
|
$test_count = get_input('test_count');
|
||||||
|
|
||||||
|
// If a URL is provided, attempt to shorten it
|
||||||
|
if ($url) {
|
||||||
|
// if a password is set, check it
|
||||||
|
if ($password !== '' && $input_password !== $password) {
|
||||||
|
http_response_code(401); // Unauthorized
|
||||||
|
echo "Unauthorized: Incorrect password.\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
// return 422 if the URL is longer than max_url_length
|
||||||
|
if (strlen($url) > $max_url_length) {
|
||||||
|
http_response_code(422); // Unprocessable Entity
|
||||||
|
echo "Invalid URL.\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
// return 403 if the URL's domain is not in the allowed list
|
||||||
|
$parsed_url = parse_url($url);
|
||||||
|
if ($parsed_url === false || !isset($parsed_url['host']) || !test_host($parsed_url['host'])) {
|
||||||
|
http_response_code(403);
|
||||||
|
echo "Forbidden: This URL is not within the list of allowed domains.\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
// validate the URL and shorten it
|
||||||
|
if (filter_var($url, FILTER_VALIDATE_URL)) {
|
||||||
|
$key = add_url($url);
|
||||||
|
$shortened_url = "https://$_SERVER[HTTP_HOST]/$key";
|
||||||
|
echo "$shortened_url\n";
|
||||||
|
} else {
|
||||||
|
http_response_code(422); // Unprocessable Entity
|
||||||
|
echo "Invalid URL.\n";
|
||||||
|
}
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If test parameters are provided, output a series of incremented keys
|
||||||
|
if ($enabed_test && $test_start !== null && $test_count !== null) {
|
||||||
|
// validate password
|
||||||
|
if ($password !== '' && $input_password !== $password) {
|
||||||
|
http_response_code(401); // Unauthorized
|
||||||
|
echo "Unauthorized: Incorrect password.\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
output_keys($test_start, (int)$test_count);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise, assume the request URI is a key to look up
|
||||||
|
$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
|
||||||
|
$key = trim($path, '/');
|
||||||
|
|
||||||
|
// If the key is valid, look up the URL and redirect
|
||||||
|
if ($key !== '') {
|
||||||
|
$url = get_url($key);
|
||||||
|
if ($url !== null) {
|
||||||
|
header("Location: $url", true, 301);
|
||||||
|
exit;
|
||||||
|
} else {
|
||||||
|
http_response_code(404);
|
||||||
|
echo "Not Found.\n";
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// If no key or url is provided, show a simple HTML form to submit a URL
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Bagaag.com Micro URL Shortener</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Bagaag.com Micro URL Shortener</h1>
|
||||||
|
|
||||||
|
<form method="post" action="">
|
||||||
|
<label for="url">Enter URL to shorten:</label><br>
|
||||||
|
<input type="text" id="url" name="url" size="50" required><br><br>
|
||||||
|
<?php if ($password !== ''): ?>
|
||||||
|
<label for="password">Enter the password:</label><br>
|
||||||
|
<input type="password" id="password" name="password" size="20" required><br><br>
|
||||||
|
<?php endif; ?>
|
||||||
|
<input type="submit" value="Shorten">
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<?php if ($enable_test): ?>
|
||||||
|
<h2>Test Key Generation</h2>
|
||||||
|
<form method="post" action="">
|
||||||
|
<label for="test_start">Generate keys from:</label><br>
|
||||||
|
<input type="text" id="test_start" name="test_start" size="50" placeholder="Leave blank to start from beginning"><br><br>
|
||||||
|
<label for="test_count">How many keys to generate:</label><br>
|
||||||
|
<input type="text" id="test_count" name="test_count" size="10" required><br><br>
|
||||||
|
<?php if ($password !== ''): ?>
|
||||||
|
<label for="password">Enter the password:</label><br>
|
||||||
|
<input type="password" id="password" name="password" size="20" required><br><br>
|
||||||
|
<?php endif; ?>
|
||||||
|
<input type="submit" value="Generate">
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
Reference in New Issue
Block a user