PHP Classes

File: App/Controllers/HomeController.php

Recommend this page to a friend!
  Packages of Amirreza Ebrahimi   URL Shortener Application   App/Controllers/HomeController.php   Download  
File: App/Controllers/HomeController.php
Role: Class source
Content type: text/plain
Description: Class source
Class: URL Shortener Application
Application to create and redirect short URLs
Author: By
Last change:
Date: 7 months ago
Size: 7,414 bytes
 

Contents

Class file image Download
<?php

namespace App\Controllers;

use
App\Core\Request;
use
App\Models\{Url, User, View};
use
App\Utilities\{Auth, ExceptionHandler, Lang};
use
HeroQR\Core\QRCodeGenerator;

/* Developed by Hero Expert
- Telegram channel: @HeroExpert_ir
- Author: Amirreza Ebrahimi
- Telegram Author: @a_m_b_r
*/
class HomeController
{
   
/**
     * Display the homepage.
     *
     * @return void Renders the home view.
     * @throws \Exception
     */
   
public function index(): void
   
{
       
view('home.index');
    }

   
/**
     * Handle URL creation and optional QR code generation.
     *
     * @param Request $request The HTTP request containing user input data.
     * @return void Renders the home view or redirects on error.
     */
   
public function createUrl(Request $request): void
   
{
        try {
           
# Check if the request is a POST with the necessary parameters
           
if ($request->method() !== 'post' && !$request->has('sub-create') && !$request->param('Url')) {
               
# Render the home view for non-POST requests
               
view('home.index');
            }

           
# Verify user authentication
           
$userEmail = Auth::checkLogin();
            if (!
$userEmail) {
                throw new \
Exception(Lang::get('Er-Login'));
            }

           
# Retrieve authenticated user
           
$user = User::where('email', $userEmail)->first();

           
# Validate the provided URL
           
$url = $request->param('Url');
            if (!
$this->validateUrl($url)) {
                throw new \
Exception(Lang::get('Er-InvalidUrl'));
            }

           
# Generate a unique short URL
           
$shortUrlData = $this->generateShortUrl();

           
# Generate QR code for the short URL
           
$qrCodePath = $this->generateQrCode($shortUrlData->url, $shortUrlData->name);

           
# Save the URL details to the database
           
$savedUrl = Url::create([
               
'created_by' => $user->id,
               
'url' => htmlspecialchars($url, ENT_QUOTES, 'UTF-8'),
               
'shortUrl' => $shortUrlData->name,
               
'qrCode' => $qrCodePath,
            ]);

           
# Handle potential save errors
           
if (!$savedUrl || !file_exists('public/QrCode/' . $shortUrlData->name . '.png')) {
                throw new \
Exception(Lang::get('Er-TryAgain'));
            }

           
# Prepare data for view
           
$data = (object)['ShortUrl' => $shortUrlData->url];

           
# Set success message and render the homepage
           
ExceptionHandler::setMessage(Lang::get('Ms-Create'));
           
view('home.index', $data);
        } catch (\
Exception $e) {
           
# Handle exceptions and redirect to the homepage with an error message
           
ExceptionHandler::setErrorAndRedirect($e->getMessage(), './');
        }
    }

   
/**
     * Redirect the user based on the shortened URL.
     *
     * @param Request $request The request containing the shortened URL parameter.
     * @return void Handles the redirect.
     */
   
public function redirectUrl(Request $request): void
   
{
        try {
           
# Retrieve the short URL parameter from the request
           
$shortUrl = $request->param('short_url');

           
# Find the corresponding URL in the database
           
$url = Url::where('shortUrl', $shortUrl)->firstOrFail();

           
# Track the view for analytics purposes
           
$this->trackView($url, $request);

           
# Redirect the user to the original URL
           
redirect($url->url);
        } catch (\
Exception) {
           
# Redirect to the homepage on error
           
redirect('./');
        }
    }

   
/**
     * Generate a unique shortened URL.
     *
     * @return object An object containing the shortened URL and its identifier.
     */
   
private function generateShortUrl(): object
   
{
        do {
           
# Generate a new short URL identifier
           
$shortUrlName = shortCreate();

           
# Check if the short URL already exists in the database
           
$exists = Url::where('shortUrl', $_ENV['APP_HOST'] . $shortUrlName)->exists();
        } while (
$exists);

       
# Return the generated short URL and its identifier
       
return (object)[
           
'url' => $_ENV['APP_HOST'] . $shortUrlName,
           
'name' => $shortUrlName
       
];
    }

   
/**
     * Generate a QR code image for a given URL.
     *
     * @param string $url The URL text to encode in the QR code.
     * @param string $name The file name for the QR code image.
     * @return string|bool The URL of the QR code image on success, false on failure.
     */
   
private function generateQrCode(string $url, string $name): string|bool
   
{
       
$savePath = BASEPATH . 'public/QrCode/' . $name;

        try {
           
# Generate and save the QR code image
           
$qrCode = new QRCodeGenerator();
           
$qrCode->setData($url)
                ->
setMargin(15)
                ->
generate('png', [
                   
'Shape' => 'S1',
                   
'Cursor' => 'C3',
                   
'Marker' => 'M3'
               
])
                ->
saveTo($savePath);

            return
$_ENV['APP_HOST'] . 'public/QrCode/' . $name . '.png';
        } catch (\
Exception) {
           
# Return false if QR code generation fails
           
return false;
        }
    }

   
/**
     * Track unique views for a given URL to prevent duplicate view counts.
     *
     * @param Url $url The URL model instance.
     * @param Request $request The HTTP request containing client information.
     * @return void Increments view count if the view is unique.
     */
   
private function trackView(Url $url, Request $request): void
   
{
       
# Retrieve client IP address and User Agent for uniqueness check
       
$ipAddress = $request->ip();
       
$userAgent = $request->agent();

       
# Check if a view from the same IP and User Agent already exists
       
$viewExists = View::where('url_id', $url->id)
            ->
where('ip_address', $ipAddress)
            ->
where('user_agent', $userAgent)
            ->
exists();

        if (!
$viewExists) {
           
# Log the unique view in the database
           
View::create([
               
'url_id' => $url->id,
               
'ip_address' => $ipAddress,
               
'user_agent' => $userAgent,
            ]);

           
# Increment the URL's view count
           
$url->increment('views');
        }
    }

   
/**
     * Validate the format and security of a URL.
     *
     * @param string $url The URL to be validated.
     * @return bool True if the URL is valid, false otherwise.
     */
   
private function validateUrl(string $url): bool
   
{
       
# Decode the URL to prevent double-encoded data.
       
$url = urldecode($url);

       
# Use filter_var to validate URL structure and ensure security.
       
return filter_var($url, FILTER_VALIDATE_URL) &&
           
preg_match("/^(https?:\/\/(?:www\.)?[a-zA-Z0-9\-\.]+(?:\.[a-zA-Z]{2,})+(?:\/[a-zA-Z0-9\-._~:\/?#[\]@!$&'()*+,;=]*)?)$|^(ftp:\/\/(?:www\.)?[a-zA-Z0-9\-\.]+(?:\.[a-zA-Z]{2,})+(?:\/[a-zA-Z0-9\-._~:\/?#[\]@!$&'()*+,;=]*)?)$|^(tel:\/\/[0-9\+\-\(\) ]+)$|^(file:\/\/[a-zA-Z0-9\-\_\/\.\:]+)$/", $url) &&
           
stripos($url, 'javascript:') === false &&
           
stripos($url, '<script>') === false &&
           
strlen($url) <= 2048;
    }
}