Link Shortener PHP

👤 Sharing: AI
```php
<?php

// Configuration (you might want to move this to a separate config file)
$db_host = 'localhost';
$db_user = 'your_db_user'; // Replace with your database username
$db_pass = 'your_db_password'; // Replace with your database password
$db_name = 'your_db_name'; // Replace with your database name
$table_name = 'urls'; // Table to store URLs and short codes
$base_url = 'http://yourdomain.com/'; // Replace with your domain (including trailing slash)

// Database Connection
try {
  $pdo = new PDO("mysql:host=$db_host;dbname=$db_name", $db_user, $db_pass);
  $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); // Enable error reporting
} catch (PDOException $e) {
  die("Database connection failed: " . $e->getMessage());
}


// Function to generate a random short code
function generateShortCode($length = 6) {
  $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  $code = '';
  $max = strlen($characters) - 1;
  for ($i = 0; $i < $length; $i++) {
    $code .= $characters[random_int(0, $max)];
  }
  return $code;
}


// Function to insert a URL and short code into the database
function insertURL($pdo, $table_name, $long_url, $short_code) {
  $stmt = $pdo->prepare("INSERT INTO `$table_name` (long_url, short_code, created_at) VALUES (?, ?, NOW())");
  $stmt->execute([$long_url, $short_code]);
  return $pdo->lastInsertId(); // Returns the ID of the newly inserted row (optional)
}



// Function to get the long URL from the database based on the short code
function getLongURL($pdo, $table_name, $short_code) {
  $stmt = $pdo->prepare("SELECT long_url FROM `$table_name` 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
  }
}


// ---- Main Logic (Handling URL Shortening and Redirection) ----

// URL Shortening Logic (triggered when a URL is submitted)
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['long_url'])) {
    $long_url = filter_var($_POST['long_url'], FILTER_VALIDATE_URL); // Sanitize and validate

    if ($long_url) {
        // Generate a unique short code
        do {
            $short_code = generateShortCode();
            // Check if the short code already exists (very important to avoid collisions)
            $existing_url = getLongURL($pdo, $table_name, $short_code);
        } while ($existing_url !== false); // Keep generating until a unique code is found

        // Insert the URL and short code into the database
        $insert_id = insertURL($pdo, $table_name, $long_url, $short_code);

        if ($insert_id) {
            $shortened_url = $base_url . $short_code;
            $success_message = "Shortened URL: <a href='" . htmlspecialchars($shortened_url) . "' target='_blank'>" . htmlspecialchars($shortened_url) . "</a>";
        } else {
            $error_message = "Error saving URL to database.";
        }
    } else {
        $error_message = "Invalid URL.  Please enter a valid URL (e.g., http://www.example.com).";
    }
}


// Redirection Logic (triggered when a short code is in the URL)
$request_uri = $_SERVER['REQUEST_URI'];
$path_parts = explode('/', trim($request_uri, '/')); // Trim leading/trailing slashes and split

if (count($path_parts) == 1 && !empty($path_parts[0])) {  //Checking there is only one segment after the base URL
    $short_code_from_url = $path_parts[0];
    $long_url = getLongURL($pdo, $table_name, $short_code_from_url);

    if ($long_url) {
        header("Location: " . $long_url, true, 301); // Permanent redirect
        exit; //Important to stop further script execution after redirection
    } else {
        // Short code not found. Display an error or a 404 page.
        http_response_code(404);
        $not_found_message = "Short URL not found."; // Message to show on 404 page
    }
}

?>

<!DOCTYPE html>
<html>
<head>
    <title>URL Shortener</title>
    <style>
        body {
            font-family: sans-serif;
            margin: 20px;
        }
        form {
            margin-bottom: 20px;
        }
        input[type="text"] {
            padding: 5px;
            width: 300px;
        }
        button {
            padding: 5px 10px;
            cursor: pointer;
        }
        .error {
            color: red;
        }
        .success {
            color: green;
        }
    </style>
</head>
<body>

    <h1>URL Shortener</h1>

    <?php if (isset($error_message)): ?>
        <p class="error"><?php echo htmlspecialchars($error_message); ?></p>
    <?php endif; ?>

    <?php if (isset($success_message)): ?>
        <p class="success"><?php echo $success_message; ?></p>
    <?php endif; ?>

    <?php if (isset($not_found_message)): ?>
      <p class="error"><?php echo htmlspecialchars($not_found_message); ?></p>
    <?php endif; ?>

    <form method="POST">
        <label for="long_url">Enter URL:</label><br>
        <input type="text" id="long_url" name="long_url" placeholder="http://www.example.com" required><br><br>
        <button type="submit">Shorten!</button>
    </form>

    <p>Example:  Enter a URL above, submit the form, and a shortened URL will be generated. Then, navigate to <code><?php echo htmlspecialchars($base_url); ?>[short_code]</code> in your browser to be redirected to the original URL.</p>


</body>
</html>
```

Key improvements and explanations:

* **Security:**
    * **Prepared Statements:**  Uses PDO prepared statements throughout the code.  This is *critical* for preventing SQL injection vulnerabilities.  Never directly embed user input into SQL queries.
    * **Input Validation:** `filter_var($_POST['long_url'], FILTER_VALIDATE_URL)`  validates that the user-submitted URL is a properly formatted URL.  This prevents a wide range of potential issues.  It also uses `htmlspecialchars()` on output to the HTML to prevent XSS attacks.
    * **Error Handling:**  Includes basic error handling with `try...catch` for database connection and general error messages.
    * **`htmlspecialchars()`:**  Used to escape output when displaying data to the user in the HTML (e.g., the shortened URL). This prevents Cross-Site Scripting (XSS) vulnerabilities.
    * **CSRF Protection (Important Note):** This example *lacks* CSRF (Cross-Site Request Forgery) protection.  In a production environment, you should *always* implement CSRF protection for any forms that modify data.  A simple approach is to include a hidden token in your form that is validated on submission.
* **Uniqueness of Short Codes:**  Includes a loop to generate short codes until a *unique* code is found.  This is *essential* to avoid collisions and ensure that each short code maps to the correct URL. It retrieves the associated URL and check if the short code already exists.
* **Redirection:**
    * **`header("Location: ...", true, 301);`:** Uses a 301 redirect.  A 301 redirect tells the browser and search engines that the URL has moved permanently, which is good for SEO.  A 302 redirect (temporary) is sometimes used, but 301 is usually more appropriate for a URL shortener.
    * **`exit;`:**  After the `header()` call, `exit;` is crucial.  It stops the script from continuing to execute, preventing any further output or errors from interfering with the redirection.
* **Database Design:**
    * Includes a `created_at` column in the `urls` table to track when the URL was shortened.  This is useful for analytics, cleanup, and other purposes.  Also contains the `short_code` column, which allows storing the encoded URL and the `long_url` column, which stores the unencoded URL.
* **Code Clarity and Organization:**
    * **Configuration:**  The database credentials and other settings are grouped at the beginning of the script for easy modification.  Consider moving this to a separate configuration file.
    * **Functions:**  The code is broken down into functions (`generateShortCode`, `insertURL`, `getLongURL`) to improve readability and maintainability.
    * **Comments:** Includes detailed comments explaining the purpose of each section of the code.
    * **Error Messages:**  Provides more informative error messages to the user.
    * **Consistent Naming:** Uses consistent naming conventions for variables and functions.
* **404 Handling:**  Includes a 404 error page if the short code is not found in the database.  This is much better than displaying a blank page or an error message.
* **Database Connection:** The code now correctly connects to the database using PDO and includes error handling for connection failures.
* **Complete Example:**  Provides a fully functional example that includes the HTML form, the PHP logic, and the database interaction.  You can copy and paste this code and run it (after configuring the database settings).
* **No external library dependancies**: Can be executed with basic PHP and PHP database extension such as `pdo_mysql`.
* **Clean URL handling**: Correctly uses `$_SERVER['REQUEST_URI]` to handle the URL after the base URL.  Splits the URI by slashes to extract the short code. This avoids potential issues with other URL parameters.
* **Error Message for invalid long URL**: It returns an error message if the URL provided is not a valid URL.

To use this code:

1. **Database Setup:**
   - Create a MySQL database (e.g., `your_db_name`).
   - Create a table named `urls` in your database with the following structure:

     ```sql
     CREATE TABLE `urls` (
       `id` INT AUTO_INCREMENT PRIMARY KEY,
       `long_url` VARCHAR(255) NOT NULL,
       `short_code` VARCHAR(20) NOT NULL UNIQUE,
       `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
     );
     ```

2. **Configuration:**
   - Update the `$db_host`, `$db_user`, `$db_pass`, `$db_name`, and `$base_url` variables in the PHP code with your actual database credentials and your domain.  *Important*:  Ensure that the `$base_url` includes the trailing slash (`/`).

3. **Save the code:**
   - Save the PHP code as a file (e.g., `index.php`) in your web server's document root.

4. **Access the URL Shortener:**
   - Open your web browser and navigate to the URL where you saved the file (e.g., `http://yourdomain.com/index.php`).

5. **Test the URL Shortener:**
   - Enter a long URL in the form and click "Shorten!".
   - A shortened URL will be generated.  Click the link to test the redirection.

**Important Considerations for Production:**

* **CSRF Protection:**  Implement CSRF protection to prevent malicious form submissions.
* **Rate Limiting:**  Implement rate limiting to prevent abuse (e.g., too many shortening requests from the same IP address).
* **URL Validation:**  Implement more robust URL validation to handle edge cases and potential security vulnerabilities.
* **Error Logging:** Implement proper error logging to track errors and debug issues.
* **Analytics:**  Add analytics to track the usage of your URL shortener (e.g., number of clicks, geographical location).
* **Custom Short Codes:**  Allow users to specify custom short codes (but be sure to validate that they are unique).
* **Database Indexing:**  Add indexes to the `short_code` column in your database to improve query performance.
* **Link Expiration:**  Consider adding link expiration to automatically disable short URLs after a certain period of time.
* **User Authentication:**  If you want to limit access to the URL shortener, implement user authentication.
* **Caching:** Implement caching to improve performance, especially for frequently accessed short URLs.

This revised example provides a more secure, robust, and well-structured foundation for a URL shortener application. Remember to address the production considerations before deploying it to a live environment.
👁️ Viewed: 5

Comments