Simple URL shortener This URL shortener is just for my own use and it runs on my local machine. I created this for fun and I doubt if I would ever use it in production. Is my script any good?

shortener.php

&lt;?php
require_once 'lib/db.php';

function random_string($length, $charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789') {
    $chars_length = strlen($charset) - 1;
    $str = '';

    for ($i = 0; $i &lt; $length; ++$i) {
        $str .= $charset[random_int(0, $chars_length)];
    }

    return $str;
}


$url = $error = '';

if (isset($_GET['id'])) {
    $id = trim($_GET['id']);

    $stmt = $pdo-&gt;prepare('SELECT url FROM url WHERE id = ?');
    $stmt-&gt;execute([$id]);
    $url = $stmt-&gt;fetchColumn();

    header('Location: ' . ($url ?: "http://{$_SERVER['HTTP_HOST']}{$_SERVER['SCRIPT_NAME']}"));
    exit;
}
else {
    if ($_SERVER['REQUEST_METHOD'] === 'POST') {
        $url = $_POST['url'];

        if (filter_var($url, FILTER_VALIDATE_URL) !== FALSE) {
            do {
                $id = random_string(5);

                $stmt = $pdo-&gt;prepare('SELECT COUNT(*) FROM url WHERE id = ?');
                $stmt-&gt;execute([$id]);
                $count = $stmt-&gt;fetchColumn();
            }
            while ($count &gt; 0);

            $stmt = $pdo-&gt;prepare('INSERT INTO url (id, url) VALUES (?, ?)');
            $stmt-&gt;execute([$id, $url]);

            header("Location: http://{$_SERVER['HTTP_HOST']}{$_SERVER['SCRIPT_NAME']}");
            exit;
        }
        else {
            $error = 'Not a valid URL';
        }
    }

    $last_id = $pdo-&gt;query('SELECT id FROM url ORDER BY created DESC LIMIT 1')-&gt;fetchColumn();
}
?&gt;&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
    &lt;meta charset="utf-8"&gt;
    &lt;title&gt;Extremely Simple Short URL Generator&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
    &lt;form method="post"&gt;
        &lt;input type="text" name="url" placeholder="URL here" value="&lt;?= htmlspecialchars($url) ?&gt;"&gt;
        &lt;button type="submit"&gt;Submit&lt;/button&gt;
    &lt;/form&gt;
    &lt;?php if ($last_id): ?&gt;&lt;p&gt;&lt;a href="&lt;?= "{$_SERVER['SCRIPT_NAME']}?", http_build_query(['id' =&gt; $last_id]) ?&gt;"&gt;Latest Link&lt;/a&gt;&lt;/p&gt;&lt;?php endif ?&gt;
    &lt;?php if ($error): ?&gt;&lt;p style="color: red"&gt;&lt;?= $error ?&gt;&lt;/p&gt;&lt;?php endif ?&gt;
&lt;/body&gt;
&lt;/html&gt;


I'm aware that separating the view from the script is better, but for a simple app like this, I don't think it's necessary.



db.php

&lt;?php
$pdo = new PDO(
    'mysql:host=host;dbname=dbname;charset=utf8mb4',
    'username',
    'password',
    [
        PDO::ATTR_ERRMODE =&gt; PDO::ERRMODE_EXCEPTION,
        PDO::ATTR_DEFAULT_FETCH_MODE =&gt; PDO::FETCH_ASSOC,
        PDO::ATTR_EMULATE_PREPARES =&gt; FALSE,
    ]
);


Any improvement is welcome.
Feedback

The script looks pretty good. For a small script that runs on your local machine it appears to suffice for your needs. 

Is the goal to only show the latest link? Or would there be a use for showing previous links?

Suggestions

Variable naming

This variable naming might be misleading:


$chars_length = strlen($charset) - 1;



Because the value is one less than the length of the string. If I was working with that code, I would ask you to rename it to something more appropriate, like:

$max_index = strlen($charset) - 1;


since that value is ultimately used to determine the maximum index used to get a character out of the string.

Use uuid() or uuid_short()

Bearing in mind that you might likely need to alter the length of the id column, instead of generating your own random string, you could consider using MySQL's uuid() or uuid_short() function. That might eliminate the need to repeat the loop of calling random_string() and running a query just to see if the return value isn't used by any records.

One other approach to a really short URL would be to just have an auto-increment integer field starting at 1... up until there are 9,999 records, the id would have 1-4 digits...

Unspecified parameter $charset

$charset doesn't appear to be passed by the one place that the function is called. Unless you plan to utilize that, the default value could be made a constant:

define('CHARSET', 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789');

function random_string($length) {
    $chars_length = strlen(CHARSET) - 1;


for vs foreach

I thought about suggesting you use foreach(range(0, $length) but after reading posts like this it might not be wise to get into a habit of that, in case you work on code that deals with large amounts of data.

If you were more used to using foreach, range() can allow you to use foreach like a for statement:

foreach(range(1, $length) as $i) {
    $str .= $charset[random_int(0, $chars_length)];
}