<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Single-file URL Shortener - Bagaag</title>
	<atom:link href="https://www.bagaag.com/single-file-url-shortener/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.bagaag.com</link>
	<description></description>
	<lastBuildDate>Wed, 01 Oct 2025 18:47:23 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://www.bagaag.com/wp-content/uploads/2025/09/cropped-bagaag-favicon-32x32.png</url>
	<title>Single-file URL Shortener - Bagaag</title>
	<link>https://www.bagaag.com</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
					<title>Single-file URL Shortener</title>
					<link>https://www.bagaag.com/single-file-url-shortener/</link>
					<comments>https://www.bagaag.com/single-file-url-shortener/#respond</comments>
		
		<dc:creator><![CDATA[matt]]></dc:creator>
		<pubDate>Wed, 01 Oct 2025 00:59:53 +0000</pubDate>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[php]]></category>
		<guid isPermaLink="false">https://www.bagaag.com/?p=311</guid>

					<description><![CDATA[Recently I decided it would be fun to write a URL shortener. Something I can run on my domain to share shortened URLs that redirect to a longer one. (If you want to skip the blah-bidy-blah, here is the code.) My requirements were fairly straightforward: While I generally prefer Python, setting it up on a [&#8230;]]]></description>
										<content:encoded><![CDATA[
<p>Recently I decided it would be fun to write a URL shortener. Something I can run on my domain to share shortened URLs that redirect to a longer one. (If you want to skip the blah-bidy-blah, <a href="https://git.bagaag.com/matt/shortener/src/branch/main/index.php">here is the code</a>.)</p>



<span id="more-311"></span>



<p>My requirements were fairly straightforward:</p>



<ol class="wp-block-list">
<li>Generate unique keys that are as short as possible.</li>



<li>Simple web interface to shorten a URL.</li>



<li>Redirect requests for generated keys to the corresponding URL.</li>



<li>Secure against external abuse.</li>



<li>Build <a href="https://www.ronjeffries.com/xprog/articles/practices/pracsimplest/">the simplest thing that works</a>.</li>
</ol>



<p>While I generally prefer Python, setting it up on a web server is something of a bother. My server already supports PHP, so I created a one-letter subdomain on bagaag.com and started with an empty PHP file. I coded in Visual Studio Code connected to the server via SSH. ♫ It’s my server and I’ll code on production if I want to! ♫</p>



<p>The first requirement was the most interesting to me. I’ve often wondered about the algorithm that sites like <a href="https://tinyurl.com/">tinyurl.com</a> use. I thought about the problem, what kind of keys I’d like to see, and came up with this algorithm:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Given a unique set of characters, iterate through each in order, adding characters as required to retain uniqueness.</p>
</blockquote>



<p>I implemented this in a function that takes as input any string the algorithm might generate and returns the next string in the sequence.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#39404f;color:#c8d0e0">PHP</span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// Unique set of characters for generating keys
$charset = 'acr8mqbs7di4tuh6e9fjv2gwx0nlk5poy1z3'; 

// 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 &gt;= 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 &lt; 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);
}</textarea></pre><svg style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" /><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// Unique set of characters for generating keys</span></span>
<span class="line"><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">charset</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">acr8mqbs7di4tuh6e9fjv2gwx0nlk5poy1z3</span><span style="color: #ECEFF4">'</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Provides the next key by incrementing the previous key.</span></span>
<span class="line"><span style="color: #616E88">// Start with empty string and then feed the return value </span></span>
<span class="line"><span style="color: #616E88">// back into this function to get the next key, and repeat.</span></span>
<span class="line"><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">increment_string</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">s</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">global</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">charset</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// convert the charset to an array of characters</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">chars</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">str_to_chars</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">charset</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// if the string is empty, return the first character</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">s</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">''</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">chars</span><span style="color: #ECEFF4">[</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">]</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// convert the input string to an array of characters</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">string</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">str_to_chars</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">s</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// iterate over the input string characters from end to beginning</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">for</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">index</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">count</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">string</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">index</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;=</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">index</span><span style="color: #81A1C1">--</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// find and validate the position of the character in the charset</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">char</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">string</span><span style="color: #ECEFF4">[</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">index</span><span style="color: #ECEFF4">]</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">pos</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">array_search</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">char</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">chars</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">pos</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">Character not in set: </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">char</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// if the character is not the last in the charset, increment </span></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">//it and break</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">pos</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&lt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">count</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">chars</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">-</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">string</span><span style="color: #ECEFF4">[</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">index</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">chars</span><span style="color: #ECEFF4">[</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">pos</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">+</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">1</span><span style="color: #ECEFF4">]</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">break;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// character is the last in the charset; wrap around to the </span></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// first character</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">string</span><span style="color: #ECEFF4">[</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">index</span><span style="color: #ECEFF4">]</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">chars</span><span style="color: #ECEFF4">[</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">]</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// if we are at the beginning of the string, prepend the first </span></span>
<span class="line"><span style="color: #ECEFF4">        </span><span style="color: #616E88">// character and break</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">index</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #88C0D0">array_unshift</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">string</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">chars</span><span style="color: #ECEFF4">[</span><span style="color: #B48EAD">0</span><span style="color: #ECEFF4">])</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">break;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">join</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">''</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">string</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p>I like this algorithm because it can be easily customized in terms of the characters it uses in the keys. The value for <code>$charset</code> came from randomizing “abcdefghijklmnopqrstuvwxyz0123456789”. I did that so the keys look meaningless to the casual observer. If you change <code>$charset</code> to <code>'abc'</code> the sequence of keys looks like this: a b c aa ab ac ba bb bc ca cb cc aaa aab aac.… So by giving it a whole bunch of characters to choose from and randomizing them, you get seemingly meaningless and unique keys that are as short as possible. </p>



<p>I could have included capital letters and exponentially increased the key capacity, but mixed case keys look messy to me and I don’t need the capacity. Without them, I’m only waist deep in four character keys at the one million mark. I’m not building a SaaS product — this is just for personal use.</p>



<p>After writing this, I did some research on how this is generally done to see how far off I was. A base-62 encoder seems like the obvious path among the various implementations I found. Instead of <a href="https://mathspp.com/blog/base-conversion-in-python#converting-an-integer-to-any-base">math</a>, I used fairly efficient string manipulation to achieve a similar result.</p>



<p>With the fun part over, I whipped up storage for the last key generated and a mapping of keys to URLs. Again, simple as possible. Even SQLite would be massive overkill here. </p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#39404f;color:#c8d0e0">PHP</span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>$last_file = 'last.txt'; // file to store the last incremented key
$urls_file = 'urls.txt'; // file to store the URLs with their 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);
}

// 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;
}</textarea></pre><svg style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" /><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">last_file</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">last.txt</span><span style="color: #ECEFF4">'</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// file to store the last incremented key</span></span>
<span class="line"><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">urls_file</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">urls.txt</span><span style="color: #ECEFF4">'</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// file to store the URLs with their keys</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Returns the contents of $last_file, or empty string if the file </span></span>
<span class="line"><span style="color: #616E88">// does not exist</span></span>
<span class="line"><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">get_last</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">global</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">last_file</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">file_exists</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">last_file</span><span style="color: #ECEFF4">))</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">trim</span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">file_get_contents</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">last_file</span><span style="color: #ECEFF4">))</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">''</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Writes to $last_file</span></span>
<span class="line"><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">set_last</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">s</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">global</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">last_file</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">file_put_contents</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">last_file</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">s</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Reads the last key, increments it, saves it, and returns it</span></span>
<span class="line"><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">next_key</span><span style="color: #ECEFF4">()</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">last</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">get_last</span><span style="color: #ECEFF4">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">next</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">increment_string</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">last</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">set_last</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">next</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">next</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Adds a URL to urls.txt and returns the generated key</span></span>
<span class="line"><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">add_url</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">global</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">urls_file</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">key</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">next_key</span><span style="color: #ECEFF4">()</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// append the key and url to urls.txt</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #88C0D0">file_put_contents</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">urls_file</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">key</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">.</span><span style="color: #88C0D0"> </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C"> </span><span style="color: #ECEFF4">'</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">.</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">.</span><span style="color: #88C0D0"> </span><span style="color: #ECEFF4">"</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">"</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">FILE_APPEND</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">key</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Looks up a key in urls.txt and returns the corresponding URL, </span></span>
<span class="line"><span style="color: #616E88">// or null if not found</span></span>
<span class="line"><span style="color: #81A1C1">function</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">get_url</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">key</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">global</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">urls_file</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">lines</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">file</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">urls_file</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">FILE_IGNORE_NEW_LINES</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">|</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">FILE_SKIP_EMPTY_LINES</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">foreach</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">lines</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">as</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">line</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">list</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">k</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">explode</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C"> </span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">line</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #B48EAD">2</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">k</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">key</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">return</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">null;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p>For security, I started by limiting the domains that can be shortened to a defined list. Then I decided I’d rather just have that be unlimited for my personal use and added a hard-coded password. You can use either or both of these options by tweaking the configuration at the top.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#39404f;color:#c8d0e0">PHP</span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// list of allowed domains for URL shortening
$allowed_domains = []; 
// password to shorten a URL, leave empty to disable password protection
$password = 'open sesame'; 
</textarea></pre><svg style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" /><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// list of allowed domains for URL shortening</span></span>
<span class="line"><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">allowed_domains</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">[]</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #616E88">// password to shorten a URL, leave empty to disable password protection</span></span>
<span class="line"><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">password</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">open sesame</span><span style="color: #ECEFF4">'</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"></span></code></pre></div>



<p>With all the necessary functions out of the way, I focused on the HTTP request handling to tie them all together. <code>get_input</code> just looks for a variable in either _GET or _POST.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.875rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#39404f;color:#c8d0e0">PHP</span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>// read input parameters
$url = get_input('url');
$input_password = get_input('password');
$key = get_input('key');

// If a URL is provided, attempt to shorten it
if ($url) {
    // if a password is set, check it
    if ($password !== '' &amp;&amp; $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) &gt; $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: Domain not allowed.\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;
}

// 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;
    }
}</textarea></pre><svg style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" /><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #616E88">// read input parameters</span></span>
<span class="line"><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">get_input</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">url</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">input_password</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">get_input</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">key</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">get_input</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">key</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// If a URL is provided, attempt to shorten it</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// if a password is set, check it</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">password</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!==</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">''</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&amp;&amp;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">input_password</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!==</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">password</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">http_response_code</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">401</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Unauthorized</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">echo</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">Unauthorized: Incorrect password.</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">exit;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// return 422 if the URL is longer than max_url_length</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">strlen</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">max_url_length</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">http_response_code</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">422</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Unprocessable Entity</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">echo</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">Invalid URL.</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">	    </span><span style="color: #81A1C1">exit;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// return 403 if the URL's domain is not in the allowed list</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">parsed_url</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">parse_url</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">parsed_url</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">===</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">false</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">!isset</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">parsed_url</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">host</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">])</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">||</span><span style="color: #D8DEE9FF"> </span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">!</span><span style="color: #88C0D0">test_host</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">parsed_url</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">host</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">]))</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">http_response_code</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">403</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">echo</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">Forbidden: Domain not allowed.</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">exit;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">    </span><span style="color: #616E88">// validate the URL and shorten it</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #88C0D0">filter_var</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">FILTER_VALIDATE_URL</span><span style="color: #ECEFF4">))</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">key</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">add_url</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">shortened_url</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">https://</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">_SERVER</span><span style="color: #A3BE8C">[HTTP_HOST]/</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">key</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">echo</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">shortened_url</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">http_response_code</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">422</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span><span style="color: #D8DEE9FF"> </span><span style="color: #616E88">// Unprocessable Entity</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">echo</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">Invalid URL.</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">exit;</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// Otherwise, assume the request URI is a key to look up</span></span>
<span class="line"><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">path</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">parse_url</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">_SERVER</span><span style="color: #ECEFF4">[</span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">REQUEST_URI</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">],</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">PHP_URL_PATH</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">key</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">trim</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">path</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #ECEFF4">'</span><span style="color: #A3BE8C">/</span><span style="color: #ECEFF4">'</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #616E88">// If the key is valid, look up the URL and redirect</span></span>
<span class="line"><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">key</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!==</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">''</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">=</span><span style="color: #D8DEE9FF"> </span><span style="color: #88C0D0">get_url</span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">key</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">if</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">(</span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">!==</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">null</span><span style="color: #ECEFF4">)</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">header</span><span style="color: #ECEFF4">(</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">Location: </span><span style="color: #81A1C1">$</span><span style="color: #D8DEE9">url</span><span style="color: #ECEFF4">"</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #81A1C1">true</span><span style="color: #ECEFF4">,</span><span style="color: #88C0D0"> </span><span style="color: #B48EAD">301</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">exit;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span><span style="color: #D8DEE9FF"> </span><span style="color: #81A1C1">else</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">{</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #88C0D0">http_response_code</span><span style="color: #ECEFF4">(</span><span style="color: #B48EAD">404</span><span style="color: #ECEFF4">)</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">echo</span><span style="color: #D8DEE9FF"> </span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">Not Found.</span><span style="color: #EBCB8B">\n</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">exit;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #ECEFF4">}</span></span>
<span class="line"><span style="color: #ECEFF4">}</span></span></code></pre></div>



<p>And finally, the bare minimum HTML to make it usable.</p>



<div class="wp-block-kevinbatdorf-code-block-pro" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1.25rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:10px 0px 10px 16px;margin-bottom:-2px;width:100%;text-align:left;background-color:#39404f;color:#c8d0e0">HTML</span><span role="button" tabindex="0" style="color:#d8dee9ff;display:none" aria-label="Copy" class="code-block-pro-copy-button"><pre class="code-block-pro-copy-button-pre" aria-hidden="true"><textarea class="code-block-pro-copy-button-textarea" tabindex="-1" aria-hidden="true" readonly>&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;title&gt;Bagaag.com Micro URL Shortener&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;h1&gt;Bagaag.com Micro URL Shortener&lt;/h1&gt;
    &lt;form method="post" action=""&gt;
        &lt;label for="url"&gt;Enter URL to shorten:&lt;/label&gt;&lt;br&gt;
        &lt;input type="text" id="url" name="url" size="50" required&gt;&lt;br&gt;&lt;br&gt;
        &lt;?php if ($password !== ''): ?&gt;
            &lt;label for="password"&gt;Enter the password:&lt;/label&gt;&lt;br&gt;
            &lt;input type="password" id="password" name="password" size="20"   
              required&gt;&lt;br&gt;&lt;br&gt;
        &lt;?php endif; ?&gt;
        &lt;input type="submit" value="Shorten"&gt;
    &lt;/form&gt;
&lt;/body&gt;
&lt;/html&gt;</textarea></pre><svg style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4" /><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2" /></svg></span><pre class="shiki nord" style="background-color: #2e3440ff" tabindex="0"><code><span class="line"><span style="color: #81A1C1">&lt;!DOCTYPE</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">html</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #81A1C1">&lt;html</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">lang</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">en</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #81A1C1">&lt;head&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;meta</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">charset</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">UTF-8</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;meta</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">name</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">viewport</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">content</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">width=device-width, initial-scale=1.0</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;title&gt;</span><span style="color: #D8DEE9FF">Bagaag.com Micro URL Shortener</span><span style="color: #81A1C1">&lt;/title&gt;</span></span>
<span class="line"><span style="color: #81A1C1">&lt;/head&gt;</span></span>
<span class="line"><span style="color: #81A1C1">&lt;body&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;h1&gt;</span><span style="color: #D8DEE9FF">Bagaag.com Micro URL Shortener</span><span style="color: #81A1C1">&lt;/h1&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;form</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">method</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">post</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">action</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">""</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;label</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">for</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">url</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">Enter URL to shorten:</span><span style="color: #81A1C1">&lt;/label&gt;&lt;br&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;input</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">type</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">text</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">id</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">url</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">name</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">url</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">size</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">50</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">required</span><span style="color: #81A1C1">&gt;&lt;br&gt;&lt;br&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">&lt;</span><span style="color: #D8DEE9FF">?php if ($password !== ''): ?&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">&lt;label</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">for</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">&gt;</span><span style="color: #D8DEE9FF">Enter the password:</span><span style="color: #81A1C1">&lt;/label&gt;&lt;br&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">            </span><span style="color: #81A1C1">&lt;input</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">type</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">id</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">name</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">password</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">size</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">20</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF">   </span></span>
<span class="line"><span style="color: #D8DEE9FF">              </span><span style="color: #8FBCBB">required</span><span style="color: #81A1C1">&gt;&lt;br&gt;&lt;br&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #D8DEE9">&lt;</span><span style="color: #D8DEE9FF">?php endif; ?&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">        </span><span style="color: #81A1C1">&lt;input</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">type</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">submit</span><span style="color: #ECEFF4">"</span><span style="color: #D8DEE9FF"> </span><span style="color: #8FBCBB">value</span><span style="color: #ECEFF4">=</span><span style="color: #ECEFF4">"</span><span style="color: #A3BE8C">Shorten</span><span style="color: #ECEFF4">"</span><span style="color: #81A1C1">&gt;</span></span>
<span class="line"><span style="color: #D8DEE9FF">    </span><span style="color: #81A1C1">&lt;/form&gt;</span></span>
<span class="line"><span style="color: #81A1C1">&lt;/body&gt;</span></span>
<span class="line"><span style="color: #81A1C1">&lt;/html&gt;</span></span></code></pre></div>



<p>Anyway, I had fun with this. It’s up and running for me at r.bagaag.com. Here is a shortened link to see it working: <a href="https://r.bagaag.com/j">https://r.bagaag.com/j</a></p>



<p><a href="https://git.bagaag.com/matt/shortener/src/branch/main/index.php" rel="nofollow">Here is the full source</a>.</p>



<p>To run it yourself, just host it on a domain of your choosing, like r.yourdomain.com. Make sure PHP has write access to the files named at the top. I recommend placing the text files outside the site root, or configure your web server to block requests to them.</p>



<p>If you just want to test it locally, use the terminal to run it like this from the directory that contains index.php:</p>



<pre class="wp-block-code"><code>$ php -S localhost:3000</code></pre>



<p>Then browse to http://localhost:3000. You’ll need to change “https” to “http” in the script if you’re not going to use HTTPS.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.bagaag.com/single-file-url-shortener/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
