<?php
/**
 * CMS HELPER CLASS
 *
 * @package
 * @author Rihards Silins
 * @copyright MTC Media 2013
 * @version 1.0 05/03/2014
 * @access public
 *
 * When this will be used more - it shall be more fledged out.
 *
 */
class CmsHelper {

    /**
     * Should be called in <head></head> in the frontend layout
     */
    public static function enablePdEdit() {

        echo '<script type="text/javascript" src="/admin/js/libs/tinymce/tinymce.min.js"></script>
<script type="text/javascript" src="/admin/js/libs/tinymce/jquery.tinymce.min.js"></script>
<script src="/admin/js/libs/pdedit.js"></script>
';

    }

    /**
     * Adds appropriate attributes for content container tags for inline frontend editing.
     */
    public static function pdEdit( $pagedata, $session=null ) {

        if ( $session === null ) {
            $session = $_SESSION;
        }

        $valid_editable_pagedata_types = array("text", "textarea");

        if ( !in_array($pagedata['type'], $valid_editable_pagedata_types) ) {

            return "";

        }

        if ( !isset($session['content_manager']['front_editing']) || $session['content_manager']['front_editing'] !== true ) {

            return "";

        }

        return "data-editable-pagedata-id=\"".$pagedata['id']."\" data-editable-pagedata-type=\"".$pagedata['type']."\"";

    }

    /**
     * CmsHelper::recursivelyRmdir
     * Recursively delete a directory that is not empty.
     * @param string $directory_name
     * @author Rihards Siliņs
     */
    public static function recursivelyRmdir($directory_name) {
        if (is_dir($directory_name)) {
            $objects = scandir($directory_name);
            foreach ($objects as $object) {
                if ($object != "." && $object != "..") {
                    if (filetype($directory_name."/".$object) == "dir") {
                        self::recursivelyRmdir($directory_name."/".$object);
                    } else {
                        unlink($directory_name."/".$object);
                    }
                }
            }
            reset($objects);
            rmdir($directory_name);
        }
    }

    /**
     * Check if file upload matches set rules.
     * Allows receiving settings for allowed file types.
     * By default disables harmful files.
     *
     * @param string $rules Mime regex for the (dis)allowed files
     * @param string $file Path to tmp_file of the uploaded file
     * @param string $file_name uploaded file name
     * @param bool $image whether add_fullcms_image is used (true) or add_fullcms_file (false)
     * @return bool whether file is allowed based on rules or not
     * @author Martins Fridenbergs <martins.fridenbergs@mtcmedia.co.uk>
     */
    public static function isFileMimeValid($rules = '', $file, $file_name, $image = false): bool
    {
        if (!is_string($file) || !is_readable($file)) return false;

        $finfo = @finfo_open(FILEINFO_MIME_TYPE);
        if ($finfo === false) return false;

        $mime = @finfo_file($finfo, $file);
        finfo_close($finfo);
        if (!is_string($mime) || $mime === '') return false;

        // Normalize extension
        $basename = preg_replace('/[\x00-\x1F\x7F]/u', '', (string)$file_name) ?? (string)$file_name;
        $parts = array_values(array_filter(explode('.', strtolower($basename))));
        $extension = end($parts) ?: '';

        // Block double/hidden dangerous extensions anywhere in the name
        $suspicious = ['php','phtml','phar','pl','py','rb','sh','bat','cmd','exe','jar','js','vb','vbs'];
        foreach ($parts as $p) {
            if (in_array($p, $suspicious, true)) return false;
        }

        // Reject any file containing PHP open tags (disguised PHP/polyglot)
        $chunk = file_get_contents($file, false, null, 0, 4096) ?: '';
        if (preg_match('/<\?(?:php|=)/i', $chunk)) return false;

        if ($image) {
            $allowedMimes = ['image/jpeg','image/png','image/gif'];
            $allowedExts  = ['jpg','jpeg','png','gif'];
            if (!in_array($mime, $allowedMimes, true)) return false;
            if (!in_array($extension, $allowedExts, true)) return false;

            // Must be a real image
            if (!@getimagesize($file)) return false;
            return true;
        } else {
            $allowedMimes = [
                'application/pdf',
                'text/plain',
                'text/csv',
                'application/vnd.ms-excel',
                'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
                'application/msword',
                'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
            ];
            $allowedExts = ['pdf','txt','csv','xls','xlsx','doc','docx'];

            if (!in_array($mime, $allowedMimes, true)) return false;
            if (!in_array($extension, $allowedExts, true)) return false;

            // Light sanity checks by type
            if ($extension === 'pdf') {
                $head = file_get_contents($file, false, null, 0, 8) ?: '';
                if (strpos($head, '%PDF-') !== 0) return false;
            }
            if (in_array($extension, ['docx','xlsx'], true)) {
                // ZIP magic: PK\x03\x04
                $zipHead = file_get_contents($file, false, null, 0, 4) ?: '';
                if ($zipHead !== "PK\x03\x04") return false;
            }
            if ($extension === 'xls') {
                // OLE CF magic: D0 CF 11 E0 A1 B1 1A E1
                $ole = bin2hex(file_get_contents($file, false, null, 0, 8) ?: '');
                if ($ole !== 'd0cf11e0a1b11ae1') return false;
            }
            if (in_array($extension, ['txt','csv'], true)) {
                // Reject binary/text with NULs
                $sample = file_get_contents($file, false, null, 0, 8192) ?: '';
                if (strpos($sample, "\0") !== false) return false;
            }
            return true;
        }
    }

    /**
     * Calculates read time based on number of words in the article.
     * Presumably an average person can read 180 words per minute
     *
     * @param $article
     * @return int
     */
    public static function calculateArticleReadTime($article)
    {
        $word_count = 0;
        $words = explode(' ', $article->pagedata['First Paragraph'][0]['value'] ?? null);
        $word_count += count($words);

        if (is_array($article->pagedata['Extra Content'])) {
            foreach ($article->pagedata['Extra Content'] as $extra_content) {
                $words = explode(' ', $extra_content['Extra Title']['value'] ?? null);
                $word_count += count($words);
                $words = explode(' ', strip_tags($extra_content['Extra Content']['value']));
                $word_count += count($words);
            }
        }

        return round($word_count / 180) ?: 1;
    }

    /**
     * Merges articles
     *
     * @param $existing_articles
     * @param $articles_to_add
     * @return array
     */
    public static function mergeArticles($existing_articles, $articles_to_add)
    {
        foreach ($articles_to_add as $article_to_add) {
            foreach ($existing_articles as $existing_article) {
                if ($existing_article->id === $article_to_add->id) {
                    continue 2;
                }
            }
            $existing_articles[] = $article_to_add;
        }

        return $existing_articles;
    }
}
