# fluent-support/1.10.2/app/Hooks/Handlers/ExternalPages.php

Fluent Support – Helpdesk &amp; Customer Support Ticket System, version 1.10.2. 213 lines.

- Page: https://pluginprobe.com/plugins/fluent-support/1.10.2/code/app/Hooks/Handlers/ExternalPages.php
- Raw: https://pluginprobe.com/plugins/fluent-support/1.10.2/raw/app/Hooks/Handlers/ExternalPages.php
- Modified: 2025-11-06T15:00:16+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/fluent-support/1.10.2/code/app/Hooks/Handlers/ExternalPages.php#L10-L20`.

```php
<?php

namespace FluentSupport\App\Hooks\Handlers;


use FluentSupport\App\Models\Attachment;
use FluentSupport\App\Models\Ticket;
use FluentSupport\App\Services\Helper;
use FluentSupport\Framework\Support\Arr;

class ExternalPages
{
    public function route()
    {
        // First verify nonce for security
        if (!isset($_REQUEST['_wpnonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])), 'fluent-support')) {
            wp_die(esc_html__('Security check failed. Please try again.', 'fluent-support'), 403);
            return;
        }

        // Then check permissions if user is logged in
        if (!get_current_user_id()) {
            wp_die(esc_html__('You do not have permission to access this page.', 'fluent-support'), 403);
            return;
        }

        $route = sanitize_text_field($_REQUEST['fs_view']);

        $methodMaps = [
            'ticket' => 'handleTicketView'
        ];

        if (isset($methodMaps[$route])) {
            $this->{$methodMaps[$route]}();
        }

    }

    public function handleTicketView()
    {
        if (!Helper::isPublicSignedTicketEnabled()) {
            $this->handleInvalidTicket();
        } else {
            $this->handleValidTicket();
        }
    }

    /**
     * Display the attachment.
     *
     * Uses the new rewrite endpoint to get an attachment ID
     * and display the attachment if the currently logged in user
     * has the authorization to.
     *
     * @return void
     * @since 3.2.0
     */
    public function view_attachment()
    {
        // First verify nonce for security
        if (!isset($_REQUEST['_wpnonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_REQUEST['_wpnonce'])), 'fluent-support')) {
            wp_die(esc_html__('Security check failed. Please try again.', 'fluent-support'), 403);
            return;
        }

        // Then check permissions if user is logged in
        if (!get_current_user_id()) {
            wp_die(esc_html__('You do not have permission to access this file.', 'fluent-support'), 403);
            return;
        }

        $attachmentHash = sanitize_text_field($_REQUEST['fst_file']);

        if (empty($attachmentHash)) {
            die('Invalid Attachment Hash');
        }

        $attachment = $this->getAttachmentByHash($attachmentHash);

        if (!$attachment) {
            die('Invalid Attachment Hash');
        }

        // check signature hash
        if (!$this->validateAttachmentSignature($attachment)) {
            $dieMessage = esc_html__('Sorry, Your secure sign is invalid, Please reload the previous page and get new signed url', 'fluent-support');
            die(esc_html($dieMessage));  // Escaping the die message again for safety
        }

        //If external file
        if ('local' !== $attachment->driver) {
            if(!empty($attachment->full_url)){
                $this->redirectToExternalAttachment($attachment->full_url);
            }else{
                die('File could not be found');
            }
        }

        //Handle Local file
        if (!file_exists($attachment->file_path)) {
            die('File could not be found');
        }
        $this->serveLocalAttachment($attachment);
    }

    private function getAttachmentByHash($attachmentHash)
    {
        return Attachment::where('file_hash', $attachmentHash)->first();
    }

    private function validateAttachmentSignature($attachment)
    {
        // Sanitize and validate secure_sign input - don't trust any input
        if (!isset($_REQUEST['secure_sign'])) {
            return false;
        }
        
        $secureSign = sanitize_text_field(wp_unslash($_REQUEST['secure_sign']));
        $sign = md5($attachment->id . date('YmdH'));
        return $sign === $_REQUEST['secure_sign'];
        // return hash_equals($sign, $secureSign);
    }

    private function handleInvalidTicket()
    {
        // Nonce already verified in route() method
        // Validate and sanitize input - don't trust any input
        $ticketId = absint(Arr::get($_REQUEST, 'ticket_id', 0));
        
        if (!$ticketId) {
            $this->showInvalidPortalMessage();
            return;
        }
        
        $ticket = Ticket::where('id', $ticketId)->first();

        if (!$ticket) {
            $this->showInvalidPortalMessage();
        } else {
            // Check permissions if user is logged in
            if (!get_current_user_id()) {
                wp_die(esc_html__('You do not have permission to access this ticket.', 'fluent-support'), 403);
                return;
            }
            $this->redirectToTicketView($ticket);
        }
    }

    private function handleValidTicket()
    {
        // Nonce already verified in route() method
        // Validate and sanitize inputs - don't trust any input
        $ticketHash = sanitize_text_field(Arr::get($_REQUEST, 'support_hash', ''));
        $ticketId = absint(Arr::get($_REQUEST, 'ticket_id', 0));
        
        if (empty($ticketHash) || !$ticketId) {
            $this->showInvalidPortalMessage();
            return;
        }
        
        $ticket = Ticket::where('hash', $ticketHash)->where('id', $ticketId)->first();

        if (!$ticket) {
            $this->showInvalidPortalMessage();
        } elseif (get_current_user_id()) {
            $this->redirectToTicketView($ticket);
        }
    }

    private function showInvalidPortalMessage()
    {
        echo '<h3 style="text-align: center; margin: 50px 0;">' . esc_html__('Invalid Support Portal URL', 'fluent-support') . '</h3>';
        die();
    }

    private function redirectToTicketView($ticket)
    {
        $redirectUrl = Helper::getTicketViewUrl($ticket);
        $this->redirectToExternalAttachment($redirectUrl);
    }

    private function redirectToExternalAttachment($redirectUrl)
    {
        wp_redirect($redirectUrl, 307);
        exit();
    }

    // Helper method to serve an attachment
    private function serveLocalAttachment($attachment)
    {
        $file_path = realpath($attachment->file_path);
        $uploads     = wp_upload_dir();
        $uploads_dir = realpath($uploads['basedir']); // Ensures both paths are absolute

        if (!$file_path || !$uploads_dir || strpos($file_path, $uploads_dir) !== 0 || !file_exists($file_path)) {
            wp_die(esc_html__('File not found or access denied', 'fluent-support'), 403);
            return;
        }
        
        ob_get_clean();
        $original_user_agent = ini_get('user_agent');
        ini_set('user_agent', 'Fluent Support/' . FLUENT_SUPPORT_VERSION . '; ' . esc_url(get_bloginfo('url')));
        
        header("Content-Type: " . esc_attr($attachment->file_type));
        header("Content-Disposition: inline; filename=\"" . esc_attr($attachment->title) . "\"");
        readfile($file_path);

        ini_set('user_agent', $original_user_agent);
        die();
    }

}

```
