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