<?php
if ( ! defined( 'ABSPATH' ) ) {
    exit;
}
/**
 * Secure SVG Uploader
 */
class Ntvb_SecureSVUploader {

    /**
     * WP_Filesystem instance
     * 
     * @var WP_Filesystem
     */
    private $wp_filesystem;

    /**
     * Constructor
     */
    public function __construct() {
        add_filter('upload_mimes', array($this, 'add_svg_mime_type'));
        add_filter('wp_handle_upload_prefilter', array($this, 'validate_svg'));
        add_filter('wp_prepare_attachment_for_js', array($this, 'fix_svg_thumbnail_display'));
        add_action('admin_init', array($this, 'add_svg_support'));
        
        // Initialize WP_Filesystem
        if (!function_exists('WP_Filesystem')) {
            require_once ABSPATH . 'wp-admin/includes/file.php';
        }
        WP_Filesystem();
        global $wp_filesystem;
        $this->wp_filesystem = $wp_filesystem;
    }

    /**
     * Add SVG mime type
     * 
     * @param array $mimes
     * 
     * @return array
     */
    public function add_svg_mime_type($mimes) {
        $mimes['svg'] = 'image/svg+xml';
        $mimes['svgz'] = 'image/svg+xml';
        return $mimes;
    }

    /**
     * Validate SVG file
     * 
     * @param array $file
     * 
     * @return array
     */
    public function validate_svg($file) {
        if ($file['type'] !== 'image/svg+xml') {
            return $file;
        }

        // Check file extension
        $ext = pathinfo($file['name'], PATHINFO_EXTENSION);
        if (!in_array($ext, array('svg', 'svgz'))) {
            $file['error'] = 'Invalid SVG file extension.';
            return $file;
        }

        // Read file content using WP_Filesystem
        if (!$this->wp_filesystem->exists($file['tmp_name'])) {
            $file['error'] = 'Unable to locate uploaded file.';
            return $file;
        }

        $content = $this->wp_filesystem->get_contents($file['tmp_name']);
        if (!$content) {
            $file['error'] = 'Unable to read SVG file.';
            return $file;
        }

        // Check for PHP tags
        if (strpos($content, '<?php') !== false || strpos($content, '<?=') !== false) {
            $file['error'] = 'SVG file contains PHP code.';
            return $file;
        }

        // Check for suspicious content
        $suspicious = array(
            'script',
            'onclick',
            'onload',
            'onunload',
            'onabort',
            'onerror',
            'onmouseover',
            'onmouseout',
            'onmousemove',
            'javascript:',
            'xlink:href',
            'data:',
            'base64',
        );

        foreach ($suspicious as $pattern) {
            if (stripos($content, $pattern) !== false) {
                $file['error'] = 'SVG file contains potentially malicious content.';
                return $file;
            }
        }

        // Sanitize SVG content
        $content = $this->sanitize_svg($content);
        
        // Write sanitized content back using WP_Filesystem
        if (!$this->wp_filesystem->put_contents($file['tmp_name'], $content)) {
            $file['error'] = 'Unable to save sanitized SVG file.';
            return $file;
        }

        return $file;
    }

    /**
     * Sanitize SVG content
     * 
     * @param string $content
     * 
     * @return string
     */
    private function sanitize_svg($content) {
        // Use libxml internal errors
        libxml_use_internal_errors(true);

        // Load SVG content
        $doc = new DOMDocument();
        $doc->loadXML($content);

        // Remove comments
        $xpath = new DOMXPath($doc);
        foreach ($xpath->query('//comment()') as $comment) {
            $comment->parentNode->removeChild($comment);
        }

        // Remove unnecessary attributes
        $elements = $doc->getElementsByTagName('*');
        foreach ($elements as $element) {
            $attributes = array();
            foreach ($element->attributes as $attribute) {
                $attributes[] = $attribute->nodeName;
            }
            foreach ($attributes as $attribute) {
                if (strpos($attribute, 'on') === 0) {
                    $element->removeAttribute($attribute);
                }
            }
        }

        // Clear any XML errors that might have been logged
        libxml_clear_errors();

        return $doc->saveXML();
    }

    /**
     * Fix SVG thumbnail display
     * 
     * @param array $response
     * 
     * @return array
     */
    public function fix_svg_thumbnail_display($response) {
        if ($response['mime'] === 'image/svg+xml') {
            $response['sizes'] = array(
                'full' => array(
                    'url' => $response['url'],
                    'width' => $response['width'],
                    'height' => $response['height'],
                    'orientation' => $response['orientation']
                )
            );
        }
        return $response;
    }

    /**
     * Add SVG support
     */
    public function add_svg_support() {
        add_filter('wp_check_filetype_and_ext', function($data, $file, $filename, $mimes) {
            $filetype = wp_check_filetype($filename, $mimes);
            return array(
                'ext' => $filetype['ext'],
                'type' => $filetype['type'],
                'proper_filename' => $data['proper_filename']
            );
        }, 10, 4);
    }
}

new Ntvb_SecureSVUploader();