view .cms/mod/template.mod.php @ 1:1d486627aa1e draft default tip

24.10
author Coffee CMS <info@coffee-cms.ru>
date Sat, 12 Oct 2024 02:51:39 +0000
parents 78edf6b517a0
children
line wrap: on
line source

<?php

$cms["modules"]["template.mod.php"] = array(
    "name"        => "template_module_name",
    "description" => "template_module_description",
    "files"       => array(
        ".cms/mod/template.mod.php",
        ".cms/css/template.css",
        ".cms/js/template.js",
        ".cms/lang/ru_RU.UTF-8/template.mod.php",
        ".cms/lang/en_US.UTF-8/template.mod.php",
        ".cms/lang/uk_UA.UTF-8/template.mod.php",
    ),
);

// Return if module disabled
if ( ! empty( $cms["config"]["template.mod.php"]["disabled"] ) ) {

    return;

} else {

    // Install
    if ( empty( $cms["config"]["template.mod.php"]["template"] ) ) {
        $cms["config"]["template.mod.php"]["template"] = "mini";
    }
    if ( empty( $cms["config"]["template.mod.php"]["scripts"] ) ) {
        $cms["config"]["template.mod.php"]["scripts"] = "";
    }

    $cms["template"] = $cms["config"]["template.mod.php"]["template"];

    if ( ! isset( $cms["config"]["template.mod.php"]["disable_write_to_disk"] ) ) {
        $cms["config"]["template.mod.php"]["disable_write_to_disk"] = true;
    }
    
    if ( ! isset( $cms["config"]["template.mod.php"]["headers"] ) ) {
        $cms["config"]["template.mod.php"]["headers"] = "cache-control: max-age=0";
    }

    if ( is_admin() ) {
        hook_add_fn( "admin", "cms_template_admin" );
        hook_add_fn( "admin_header",  "cms_template_admin_header" );
        hook_add_fn( "api", "cms_template_api" );
    }
    // Вызов функции cms_template_template сделаем пораньше,
    // чтобы в других модулях не нужно было ставить 20
    hook_add_fn( "template", "cms_template_template", 5 );
    hook_add_fn( "echo", "cms_template_echo" );
    hook_add_fn( "write", "cms_template_write" );

}

function cms_template_admin_header() {
    global $cms;
    $conf = $cms["config"]["template.mod.php"]["menu"]["template"];
    if ( empty( $conf["hide"] ) && empty( $cms["config"]["admin_sections"][ $conf["section"] ]["hide"] ) ) {
        echo "<link rel=stylesheet href='{$cms['base_path']}css/template.css'>";
        echo "<script src='{$cms['base_path']}js/template.js'></script>";
    }
}

function cms_template_admin() {
    global $cms;

    $conf = $cms["config"]["template.mod.php"]["menu"]["template"];
    if ( empty( $conf["hide"] ) && empty( $cms["config"]["admin_sections"][ $conf["section"] ]["hide"] ) ) {

    // Save settings
    if ( ! empty( $_POST["save_template"] ) ) {
        $cms["config"]["template.mod.php"]["template"] = $_POST["template"];
        $cms["config"]["template.mod.php"]["disable_write_to_disk"] = empty( $_POST["enable_cache"] );
        cms_save_config();
        cms_clear_cache();
        header( "Location: {$cms['base_path']}{$cms['config']['admin.mod.php']['admin_url']}" );
        $cms["hooks"]["admin"]["next"] = ""; // Предотвратить выдачу админки
        return;
    }
    
    // Save template headers
    if ( ! empty( $_POST["save_template_headers"] ) ) {
        $cms["config"]["template.mod.php"]["headers"] = $_POST["template_headers"];
        cms_save_config();
        header( "Location: {$cms['base_path']}{$cms['config']['admin.mod.php']['admin_url']}" );
        $cms["hooks"]["admin"]["next"] = ""; // Предотвратить выдачу админки
        return;
    }

    // Create menu item
    if ( empty( $cms["config"]["template.mod.php"]["menu"]["template"] ) ) {
        $cms["config"]["template.mod.php"]["menu"]["template"] = array(
            "title"    => "template_module_name",
            "sort"     => 70,
            "section"  => "settings",
        );
        cms_save_config();
    }

    $options = "";
    foreach( glob( "{$cms['cms_dir']}/*/html.php" ) as $path_html_php ) {
        $template = preg_replace( "/.*\/([^\/]+)\/html\.php/u", "$1", $path_html_php );
        if ( substr( $template, 0, 6 ) !== "admin." ) {
            $options .= "<div class=option value='{$template}'>{$template}</div>";
        }
    }

    cms_template_load_settings();
    $template_files_title = "<div class=title>" . __( "editable_files" ) . "</div>";
    $template_files = "";
    if ( isset( $cms["templates"] ) && is_array( $cms["templates"] ) ) {
        foreach( $cms["templates"][ $cms["config"]["template.mod.php"]["template"] ]["files"] as $file ) {
            $template_files .= "<div class=file>{$file}</div>";
        }
    }
    if ( empty( $template_files ) ) {
        $template_files = "<div class=no-files>" . __( "no_editable_files" ) . "</div>";
    }
    
    $tr_title   = __( "help" );
    $tr_current = __( "current_template" );
    $tr_save    = __( "save" );
    $tr_upl     = __( "install_template" );
    if ( $cms["config"]["template.mod.php"]["disable_write_to_disk"] ) {
        $enable_cache = "";
    } else {
        $enable_cache = "checked";
    }
    $headers_title = __( "headers_title" );

    // Справка для шаблона определяется в файле template.settings.php
    $help = __( "help", $cms["config"]["template.mod.php"]["template"] );
    if ( $help === "help" ) $help = "";

    // Display settings
    $page = "
<div class=settings>
    <div class=template-install>
        <div class=upload_dnd>
            <input id=template-upload type=file name='myfile[]' multiple class=files>
            {$tr_upl}
        </div>
    </div>
    <div class=template>
        <form method=post>
            <div>{$tr_current}</div>
            <input name=template autocomplete=off type=hidden value='{$cms["config"]["template.mod.php"]["template"]}'>

            <div class=template-select-grid>
                <div class=field-select>
                    <div class=value>{$cms["config"]["template.mod.php"]["template"]}</div>
                    <div class=icon></div>
                </div>
                <div class=field-options>
                    {$options}
                </div>
            </div>

            <label>
                <input type=checkbox name=enable_cache {$enable_cache}>
                <span class=enable-cache>" . __( "enable_cache" ) . "</span>
            </label>
            
            <button name=save_template value=save>{$tr_save}</button>
        </form>
    </div>
    <form method=post class=template-headers>
        <div class=template-headers-title>{$headers_title}</div>
        <textarea name=template_headers>{$cms['config']['template.mod.php']['headers']}</textarea>
        <button name=save_template_headers value=save>{$tr_save}</button>
    </form>
    <div class=template-manual>
        <div>{$tr_title}</div>
        {$help}
    </div>
    <div class=template-files>
        {$template_files_title}
        {$template_files}
    </div>
</div>

<div class='template-editor-bg hidden'>
    <div class=template-editor-grid>
        <div class=template-editor-header>
            <div class=close-template-button></div>
            <div class=save-template-button></div>
            <span class=template-editor-title></span>
        </div>
        <div class=template-editor>
            <textarea></textarea>
        </div>
        <div class=snip-grid>
            <div class=css>
                <div data-type=snip data-otag='@media (min-width: px) and (max-width: px) {\n' data-ctag='\n}'>@media (min) and (max)</div>
                <div data-type=snip data-otag='/* ' data-ctag=' */'>/* comment */</div>
                <a href='{$cms['base_path']}man/{$cms['config']['locale']}/hint_css.html' target=_blank>" . __( "hint_css" ) . "</a>
            </div>
            <div class=php>
                <a href='{$cms['base_path']}man/{$cms['config']['locale']}/hint_php.html' target=_blank>" . __( "hint_php" ) . "</a>
            </div>
            <div class=html>
                <a href='{$cms['base_path']}man/{$cms['config']['locale']}/hint_html.html' target=_blank>" . __( "hint_html" ) . "</a>
            </div>
        </div>
    </div>
</div>
";

    $cms["admin_pages"]["template"] = $page;

    }

}

// Load template settings
function cms_template_load_settings() {
    global $cms;
    $settings = "{$cms['cms_dir']}/{$cms['config']['template.mod.php']['template']}/template.settings.php";
    if ( file_exists( $settings ) ) {
        include( $settings );
    }
}


function cms_template_api() {
    global $cms;
    
    if ( ! empty( $_POST["fn"] ) ) {
        
        switch ( $_POST["fn"] ) {

            case "clear_cache":
                cms_clear_cache();
                echo( json_encode( array(
                    "info_text"  => __( "cache_cleared" ),
                    "info_class" => "info-success",
                    "info_time"  => 5000,
                ) ) );
                return;
            break;

            case "get_template_file":
                $file = file_get_contents( $cms["site_dir"] . "/" . $_POST["file"] );
                if ( $file !== false ) {
                    $ok = "true";
                } else {
                    $ok = "false";
                }
                echo( json_encode( array(
                    "ok"   => $ok,
                    "file" => $file,
                ) ) );
                return;
            break;

            case "save_template_file":
                $file = file_put_contents( $cms["site_dir"] . "/" . $_POST["file"], $_POST["content"] );
                if ( $file !== false ) {
                    $ok    = "true";
                    $msg   = __( "saved" );
                    $class = "info-success";
                } else {
                    $ok    = "false";
                    $msg   = __( "save_error" );
                    $class = "info-error";
                }
                cms_clear_cache();
                echo( json_encode( array(
                    "ok"         => $ok,
                    "info_text"  => $msg,
                    "info_class" => $class,
                    "info_time"  => 5000,
                ) ) );
                return;
            break;

            case "install_template":
                $success = true;
                //$text = "dev.coffee-cms.ru";
                //if ( $cms["url"]["host"] !== $text )
                foreach ( $_FILES["myfile"]["name"] as $n => $name ) {
                    if ( $_FILES["myfile"]["error"][$n] ) {
                        $success = false;
                        $text = str_replace( "xxx", $name, __( "upload_error_xxx" ) );
                        break;
                    } else {
                        // Unpack Template
                        // Object Oriented Style for future compability with PHP 8
                        $zip = new ZipArchive;
                        if ( $zip->open( $_FILES["myfile"]["tmp_name"][$n] ) === TRUE ) {
                            $zip->extractTo( $cms["site_dir"] );
                            $zip->close();
                            $text = __( "install_success" );
                        } else {
                            $success = false;
                            $text = str_replace( "xxx", $name, __( "cant_unzip_xxx" ) );
                            break;
                        }
                    }
                }

                if ( $success ) {
                    echo( json_encode( array(
                        "info_text"  => $text,
                        "info_class" => "info-success",
                        "info_time"  => 5000,
                    ) ) );
                    return;
                } else {
                    echo( json_encode( array(
                        "info_text"  => $text,
                        "info_class" => "info-error",
                        "info_time"  => 10000,
                    ) ) );
                    return;
                }
            break;

        }
    }
}


function cms_template_template() {
    global $cms;
    if ( is_file( $cms["cms_file"] ) ) {
        if ( substr( $cms["cms_file"], -4 ) === ".php" || strpos( substr( $cms["cms_file"], strlen( $cms["cms_dir"] ) ), "/." ) !== false ) {
            $cms["status"]         = "404";
        } else {
            $cms["output"]["from"] = $cms["cms_file"];
            $cms["output"]["to"]   = $cms["site_dir"] . "/" . $cms["url"]["path"];
            $cms["status"]         = "200";
        }
    } else {
        ob_start();
        include( "{$cms['cms_dir']}/{$cms['template']}/html.php" );
        $cms["output"] = ob_get_clean();
    }
}


function cms_template_echo() {
    global $cms;

    $headers = array();
    if ( substr( $cms["template"], 0, 6 ) !== "admin." ) {
        $lines = explode( "\n", $cms["config"]["template.mod.php"]["headers"] );
        foreach ( $lines as $line ) {
            $line = trim( $line );
            if ( ! empty( $line ) ) {
                $headers[] = $line;
            }
        }
    }

    if ( is_array( $cms["output"] ) ) {
        if ( $cms["status"] === "200" ) {
            $types = array(
                "css" => "text/css",
                "js" => "application/javascript",
                "svg" => "image/svg+xml",
            );
            $ext = preg_replace( "/.*\./u", "", $cms["output"]["to"] );
            if ( isset( $types[$ext] ) ) {
                $mime = $types[$ext];
            } else {
                $mime = "";
            }
            header( "Content-Type: {$mime}" );
            header( "{$_SERVER['SERVER_PROTOCOL']} 200 OK" ); // fix server 404
            foreach ( $headers as $header ) {
                header( $header );
            }
            cms_readfile( $cms["output"]["from"], false );
        } else {
            header( "{$_SERVER['SERVER_PROTOCOL']} 404 Not Found" );
        }
    } else {
        switch ( $cms["status"] ) {
            case "200":
                header( "{$_SERVER['SERVER_PROTOCOL']} 200 OK" ); // fix server 404
                foreach ( $headers as $header ) {
                    header( $header );
                }
                echo $cms["output"];
            break;
            case "404":
                header( "{$_SERVER['SERVER_PROTOCOL']} 404 Not Found" );
                echo $cms["output"];
                // Для админа выводится текст страницы
                // а для анонима сообщение что не найдена
            break;
            case "301":
                header( "Location: {$cms['status_301_location']}", true, 301 );
            break;
            case "302":
                header( "Location: {$cms['status_302_location']}", true, 302 );
            break;
        }
    }
}


function cms_template_write() {
    global $cms;

    if ( ! empty( $cms["config"]["template.mod.php"]["disable_write_to_disk"] ) ) {
        return;
    }

    if ( $cms["status"] !== "200" ) {
        return;
    }
    
    // write to disk
    umask( 0 );

    if ( is_array( $cms["output"] ) ) {
        
        $dirs = explode( "/", str_replace( $cms["site_dir"] . "/", "", $cms["output"]["to"] ) );
        $dir  = $cms["site_dir"];
        $file_name = array_pop( $dirs );
        foreach ( $dirs as $path ) {
            $dir .= "/" . $path;
            if ( ! is_dir( $dir ) ) {
                mkdir( $dir, 0777, false );
            } elseif( is_file( $dir ) ) {
                unlink( $dir );
                mkdir( $dir, 0777, false );
            }
        }

        if ( ! file_exists( $cms["output"]["to"] ) ) {
            $tmp_name = $cms["site_dir"] . "/uploads/.tmp_" . cms_uid() . "_" . pathinfo( $cms["output"]["to"], PATHINFO_BASENAME );
            copy( $cms["output"]["from"], $tmp_name );
            rename( $tmp_name, $cms["output"]["to"] );
        }

    } else {

        // create dirs
        $dirs = explode( "/", $cms["url"]["path"] );
        $dir  = $cms["site_dir"];
        $file_name = array_pop( $dirs );
        foreach ( $dirs as $path ) {
            $dir .= "/" . $path;
            if ( ! file_exists( $dir ) ) {
                mkdir( $dir, 0777, false );
            } elseif( is_file( $dir ) ) {
                unlink( $dir );
                mkdir( $dir, 0777, false );
            }
        }

        if ( ! $file_name ) {
            $file = $dir . "/index.html";
        } else {
            $file = $dir . "/" . $file_name;
        }

        if ( ! file_exists( $file ) ) {
            $tmp_name = $cms["site_dir"] . "/uploads/.tmp_" . cms_uid() . "_" . pathinfo( $file, PATHINFO_BASENAME );
            file_put_contents( $tmp_name, $cms["output"], LOCK_EX );
            chmod( $tmp_name, 0666 );
            rename( $tmp_name, $file );
        }

    }
}


function cms_clear_cache() {
    global $cms;

    do_hook( "clear_cache" );

    // array for delete dirs
    $dirs = array();

    // search all pages in database
    if ( ! empty( $cms["base"] ) ) {
        if ( $res = mysqli_query( $cms["base"], "SELECT `url` FROM `pages`" ) ) {
            while ( $page = mysqli_fetch_assoc( $res ) ) {
                if ( $page["url"] === "/" ) $page["url"] = "";
                $file = $cms["site_dir"] . "/" . $page["url"];
                if ( substr( $file, -1 ) === "/" ) {
                    $file .= "index.html";
                } elseif ( is_dir( $file ) ) {
                    // for
                    // /parent/child
                    // /parent
                    $file .= "/index.html";
                }
                if ( is_file( $file ) ) unlink( $file );
                // Add dirs to remove queue
                $dir = "/" . $page["url"];
                while ( $dir && $dir !== "/" && $dir !== "\\" ) {
                    $new_dir = $cms["site_dir"] . $dir;
                    if ( ! in_array( $new_dir, $dirs ) ) {
                        $dirs[] = $new_dir;
                    }
                    $dir = dirname( $dir );
                }
            }
        }
    }

    // delete template files
    $queue[] = $cms["cms_dir"];
    while ( $cur = array_shift( $queue ) ) {
        if ( is_dir( $cur ) ) {
            // add current dir to array for delete
            array_push( $dirs, str_replace( ".cms/", "", $cur ) );
            // search children files and dirs
            $queue = array_merge( $queue, glob( $cur . "/*" ) );
        } else {
            $file = str_replace( ".cms/", "", $cur );
            if ( is_file( $file ) ) unlink( $file );
        }
    }

    // delete dirs
    rsort( $dirs );
    foreach ( $dirs as $dir ) {
        if ( is_dir( $dir ) && $dir !== $cms["cms_dir"] && $dir !== $cms["site_dir"] ) {
            if ( is_dir_and_empty( $dir ) ) {
                rmdir( $dir );
            }
        }
    }

}