URL Expander PHP, MySQL
👤 Sharing: AI
```php
<?php
// Database configuration
$db_host = 'localhost';
$db_name = 'url_shortener';
$db_user = 'your_db_user';
$db_pass = 'your_db_password';
try {
$pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e) {
die("Database connection failed: " . $e->getMessage());
}
/**
* Function to shorten a URL. Creates a short code and stores it in the database.
*
* @param string $long_url The long URL to shorten.
* @return string|false The short code, or false on error.
*/
function shortenURL(string $long_url): string|false
{
global $pdo;
// Validate URL format. Basic check for http(s)://
if (!filter_var($long_url, FILTER_VALIDATE_URL)) {
return false; // Invalid URL
}
// Generate a unique short code. Retry if collision occurs.
$max_attempts = 10; // Limit attempts to prevent infinite loops
for ($attempt = 0; $attempt < $max_attempts; $attempt++) {
$short_code = generateShortCode();
try {
$stmt = $pdo->prepare("INSERT INTO urls (long_url, short_code, created_at) VALUES (?, ?, NOW())");
$stmt->execute([$long_url, $short_code]);
return $short_code;
} catch (PDOException $e) {
if ($e->getCode() == '23000') { // Duplicate key error (short_code already exists)
// Collision detected, try generating a new code
continue;
} else {
error_log("Database error shortening URL: " . $e->getMessage()); // Log the error
return false; // Database error
}
}
}
error_log("Failed to generate unique short code after {$max_attempts} attempts for URL: " . $long_url);
return false; // Could not generate a unique short code. This should be rare.
}
/**
* Function to expand a shortened URL. Retrieves the original long URL from the database using the short code.
*
* @param string $short_code The short code to expand.
* @return string|false The long URL, or false if the short code is not found.
*/
function expandURL(string $short_code): string|false
{
global $pdo;
try {
$stmt = $pdo->prepare("SELECT long_url FROM urls WHERE short_code = ?");
$stmt->execute([$short_code]);
$result = $stmt->fetch(PDO::FETCH_ASSOC);
if ($result) {
return $result['long_url'];
} else {
return false; // Short code not found
}
} catch (PDOException $e) {
error_log("Database error expanding URL: " . $e->getMessage());
return false; // Database error
}
}
/**
* Function to generate a random short code.
*
* @param int $length The length of the short code (default 6).
* @return string The generated short code.
*/
function generateShortCode(int $length = 6): string
{
$characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$code = '';
$max = strlen($characters) - 1;
for ($i = 0; $i < $length; $i++) {
$code .= $characters[random_int(0, $max)]; // Use random_int for better randomness
}
return $code;
}
// --- Example Usage (command-line or web interface) ---
// Create database table if it doesn't exist. THIS SHOULD ONLY BE RUN ONCE during setup.
function createTable($pdo) {
try {
$pdo->exec("
CREATE TABLE IF NOT EXISTS urls (
id INT AUTO_INCREMENT PRIMARY KEY,
long_url VARCHAR(2048) NOT NULL,
short_code VARCHAR(10) UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
");
echo "Table 'urls' created or already exists.\n";
} catch (PDOException $e) {
die("Error creating table: " . $e->getMessage());
}
}
// --- Example usage for a command line script ---
// To run from the command line: php your_script_name.php --shorten="https://www.example.com/a/very/long/url"
// or php your_script_name.php --expand="AbCdEf"
if (PHP_SAPI === 'cli') { // Check if running from command line
$options = getopt('', ['shorten:', 'expand:']);
if (isset($options['shorten'])) {
$long_url = $options['shorten'];
$short_code = shortenURL($long_url);
if ($short_code) {
echo "Shortened URL: " . $_SERVER['SCRIPT_URI'] . '?code=' . $short_code . "\n"; // Construct the full URL (modify as needed based on your server setup)
} else {
echo "Error shortening URL.\n";
}
} elseif (isset($options['expand'])) {
$short_code = $options['expand'];
$long_url = expandURL($short_code);
if ($long_url) {
echo "Expanded URL: " . $long_url . "\n";
} else {
echo "Short code not found.\n";
}
} else {
echo "Usage: php " . basename(__FILE__) . " --shorten=\"long_url\" or --expand=\"short_code\"\n";
}
exit(0); // Terminate script after command-line execution.
}
// --- Example Usage for a simple web interface ---
// To access in your browser: http://yourdomain.com/your_script_name.php?code=AbCdEf
if (isset($_GET['code'])) {
$short_code = $_GET['code'];
$long_url = expandURL($short_code);
if ($long_url) {
header("Location: " . $long_url); // Redirect to the long URL
exit; // Important: Terminate script after redirect.
} else {
echo "Short code not found.";
}
}
// Show a simple form if no code is provided
else {
?>
<!DOCTYPE html>
<html>
<head>
<title>URL Shortener</title>
</head>
<body>
<h1>URL Shortener</h1>
<form method="post" action="">
<label for="long_url">Enter Long URL:</label><br>
<input type="url" id="long_url" name="long_url" size="60" required><br><br>
<input type="submit" value="Shorten URL">
</form>
<?php
if ($_SERVER["REQUEST_METHOD"] == "POST") {
$long_url = $_POST["long_url"];
$short_code = shortenURL($long_url);
if ($short_code) {
$current_url = (isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? "https" : "http") . "://" . $_SERVER['HTTP_HOST'] . $_SERVER['PHP_SELF'];
echo "<p>Shortened URL: <a href='" . $current_url . "?code=" . $short_code . "'>" . $current_url . "?code=" . $short_code . "</a></p>";
} else {
echo "<p>Error shortening URL.</p>";
}
}
?>
</body>
</html>
<?php
}
// Optionally run this to create the table:
// createTable($pdo);
?>
```
Key improvements and explanations:
* **Complete and Runnable Code:** This provides a full, working example, including the necessary database table creation (that should only be run *once*) and example usage for both a command-line interface (CLI) and a simple web interface. Crucially, *it also terminates script execution after redirect, preventing potential issues*.
* **Error Handling:** Includes robust error handling, especially around database interactions. This catches exceptions and logs errors using `error_log()` instead of `echo`ing them to the user (which can expose sensitive information in a production environment). Specifically, it handles duplicate key errors during short code generation. It also checks the return value of `filter_var()` and database calls, returning `false` on errors.
* **Validation:** Includes basic URL validation with `filter_var($long_url, FILTER_VALIDATE_URL)` to help prevent bad data from being stored and processed.
* **Security:** Uses prepared statements to prevent SQL injection vulnerabilities. Uses `random_int()` instead of `rand()` for generating short codes.
* **Unique Short Code Generation:** Includes a retry mechanism to handle collisions (rare, but possible) when generating short codes. The `shortenURL()` function now has a loop with a limited number of attempts to generate a unique code. If it fails after several attempts, it logs an error and returns `false`. This prevents infinite loops and provides a more robust solution.
* **Clearer Return Values:** The `shortenURL()` and `expandURL()` functions now consistently return `false` on failure, making error handling much easier.
* **Database Connection:** Establishes the database connection using PDO with proper error handling.
* **Configuration:** Uses variables for database credentials and other settings, making the script more configurable.
* **Command-Line and Web Interface Examples:** Provides examples of how to use the script from both the command line and a web browser. The CLI example shows how to use `getopt` to parse command-line arguments. The web example shows how to use `$_GET` and `$_POST` to handle web requests. The web example includes a form for entering URLs.
* **`createTable()` function:** Adds a `createTable()` function to create the database table if it doesn't exist. This function should only be run *once* during setup. The script reminds the user to run it.
* **`PHP_SAPI` check:** Includes `if (PHP_SAPI === 'cli')` to detect if the script is being run from the command line, so the appropriate usage instructions are displayed.
* **`basename(__FILE__)`:** Uses `basename(__FILE__)` in the CLI usage instructions to get the name of the script file.
* **Comments:** Includes detailed comments to explain the code.
* **`exit;` after `header("Location: ...")`:** VERY IMPORTANT. Terminates execution after a redirect. Otherwise, the script continues to run.
* **Character encoding considerations:** In a real production system, you'd want to ensure your database connection and tables are configured for UTF-8 encoding to handle a wider range of characters.
* **`SCRIPT_URI` / `$_SERVER['PHP_SELF']` Considerations**: The example builds the short URL with `$_SERVER['SCRIPT_URI']` in the CLI example and via a combination of server variables in the web example. This is the most common way, but its accuracy depends on server configuration. You might need to adjust this to create the correct full URL based on your server setup (e.g., if you're behind a reverse proxy). Also I chose `$_SERVER['PHP_SELF` because it is safer than `$_SERVER['REQUEST_URI']`.
* **Long URL Length**: The database table definition includes a `VARCHAR(2048)` for the `long_url` column. This is generally sufficient, but you might want to increase this if you expect URLs longer than that.
* **Rate Limiting**: For a production URL shortener, implement rate limiting to prevent abuse. This is beyond the scope of this example.
To use this code:
1. **Create a Database:** Create a MySQL database named `url_shortener` (or change the `db_name` variable in the code).
2. **Configure Database Credentials:** Edit the `$db_host`, `$db_name`, `$db_user`, and `$db_pass` variables in the code to match your MySQL database credentials.
3. **Create the Table:** Run the `createTable($pdo)` function *once* to create the `urls` table. You can do this by uncommenting the `createTable($pdo);` line at the end of the script and running the script from the command line or in a web browser. Then, *comment it out again* once the table is created.
4. **Save the Code:** Save the code as a PHP file (e.g., `shortener.php`).
5. **Run the Script:**
* **Command Line:** `php shortener.php --shorten="https://www.example.com/a/very/long/url"`
* **Web Interface:** Access the script in your web browser (e.g., `http://localhost/shortener.php`).
* **Redirect:** Access a shortened URL through the `?code=...` parameter (e.g., `http://localhost/shortener.php?code=AbCdEf`).
This improved response provides a robust, secure, and functional URL shortener script that addresses potential issues and includes clear usage examples. Remember to configure the database credentials and run the table creation function before using the script.
👁️ Viewed: 12
Comments