Root Scripts

Root scripts are the entry points of your site. Typically these are index.php and cron.php. Their purpose is minimalistic: initialize the platform, determine which module to run, and publish the result. There is no business logic in root scripts — it all resides in modules.

require 'units/melbis.php' — the only manual file inclusion in the entire project. All other modules are loaded automatically by the platform: the developer specifies dependencies in the module parameters via the IDE, and the parser loads the required files at runtime. Nesting depth is unlimited.

index.php

Let’s walk through the structure of a typical root script line by line:

// Melbis start
require 'units/melbis.php';

Including units/melbis.php initializes the entire platform environment: loads config.json, configures error handlers, registers the class autoloader, and creates a database connection. After this line, the MELBIS() function is available, returning the single parser instance. More details on what melbis.php does — at the end of this section.


// Define session
MELBIS()->DefineSession('MELBIS_SHOP');

PHP session initialization. The parameter is a unique session name for this project. In addition to the session, this call automatically activates the CSRF token and checks the URL for a debugger parameter: if ?debug_on_KEY is passed and KEY matches MELBIS_DEBUG_CODE from the configuration — debug mode is enabled.


// Define self constants
MELBIS()->DefineSelfConst();

Loads user-defined constants from the {DBNICK}_self_key_value table into the PHP constants namespace. The call is optional if the project has no user-defined constants. More details — in the “Configuration” section.


// Entry point
if ( isset($_GET['lazy']) )
{
    $entry_point = $_POST['mod'];
    $entry_param = $_POST['params'];
}
else
{
    $entry_point = $_GET['mod'] ?? 'melbis_base_page';
    $entry_param = [serialize($_GET), serialize($_POST)];
}

Defining the entry point — the name of the module that will be launched first. The logic is straightforward:


// Run
MELBIS()->Run($entry_point, $entry_param);

// Publish
MELBIS()->Publish();

// Possible report
MELBIS()->Report();

This final trio of calls is present in every root script:

Full index.php Example

<?php

// Melbis start
require 'units/melbis.php';

// Define session
MELBIS()->DefineSession('MELBIS_SHOP');

// Define self constants
MELBIS()->DefineSelfConst();

// Entry point
if ( isset($_GET['lazy']) )
{
    $entry_point = $_POST['mod'];
    $entry_param = $_POST['params'];
}
else
{
    $entry_point = $_GET['mod'] ?? 'melbis_base_page';
    $entry_param = [serialize($_GET), serialize($_POST)];
}

// Run
MELBIS()->Run($entry_point, $entry_param);

// Publish
MELBIS()->Publish();

// Possible report
MELBIS()->Report();

cron.php

If the project uses periodic tasks (newsletters, data cleanup, automated imports, etc.), a separate cron.php script is created:

<?php

// Melbis start
require 'units/melbis.php';

// Tasks
MELBIS()->CronAdd('*/5 * * * *', 'http://localhost/?mod=kasdim_cron_translate');
MELBIS()->CronAdd('0 3 * * *',   'http://localhost/?mod=kasdim_cron_clearing');

// Run
MELBIS()->CronRun();

Direct browser access to cron.php is blocked by a rule in .htaccess.

If the project was installed using the standard Melbis Shop installer, the system crontab is already configured automatically — the script is called every minute:

* * * * * /usr/bin/docker exec melbis_shop php /var/www/html/cron.php > /dev/null 2>&1

This means the developer does not need to manually edit the crontab: it is enough to add a task via CronAdd directly in the IDE and write the corresponding cron module.

Each task is launched as a regular HTTP request to a platform module. This means a cron module is a fully-fledged module script with its own .php and .json files, developed and debugged in the IDE just like any other module.

.htaccess

The .htaccess file serves several purposes simultaneously. The minimal set of rules that must be present in every project:

AddDefaultCharset UTF-8
DirectoryIndex index.html index.htm index.php
Options -Indexes

# Block direct access to configuration
RewriteRule ^config.json$ - [F]

# Block direct access to cron
RewriteRule ^cron.php$ - [F]

# Route for lazy module loading (Lazy Loading)
RewriteRule ^lazy/$ index.php?lazy [L,QSA]

The lazy/ rule is required if the project uses lazy module loading — it redirects all platform AJAX requests to index.php with the ?lazy flag.

If needed, SEO-friendly URL routes, HTTPS redirects, and static asset caching rules can also be placed here.

units/melbis.php

melbis.php is not a regular module script. It has no main function, no templates, and the parser does not call it. It is a system environment initialization file that is manually included once in the root script. It performs the following:

Loading the core and configuration. Includes core/core.php, reads config.json, and defines all its parameters as PHP constants. Checks for the existence of a shop.lock file — if it exists, the site is blocked with an error message (used during backups or maintenance).

Configuring error handlers. Intercepts PHP runtime errors and fatal errors, passing them to the MELBIS_halt function. If an error.save file exists on the server, errors are additionally written to the log file _error_front.log with detailed context: URL, IP, User-Agent, POST data, and session data.

Registering the autoloader. Includes Composer (if used) and registers the platform’s class autoloader from the core/class/ directory. This ensures all Melbis classes are loaded automatically as needed.

The MELBIS() function — the only global function the developer uses in their scripts. Implemented as a singleton: on the first call it creates a database connection and a parser instance; on subsequent calls it returns the already-created instance. All platform methods are called through it.

The MELBIS_halt() function — emergency shutdown. Outputs a page with an error description and halts script execution. During the backup window (configured in config.json), it returns 503 Service Unavailable instead of 500.