Technical Reference

Widget Storm v4.0.0 — System documentation

1. System Overview

Widget Storm is a modular widget platform for the web, active since 2008. Widgets are self-contained web components made of three layers (PHP, CSS, JavaScript), stored encrypted on the server and delivered over HTTP endpoints.

PropertyValue
Version4.0.0
LanguagePHP 8.3
DatabaseMySQL / MariaDB
EncryptionRIJNDAEL-256 (Legacy), AES-256-CBC (Modern)
Default authorWidgetStormSystem
Execution contextsLocal (wgclient.php), Remote (wgcall.php), Client-side (wghandler.php)
For a guided introduction with interactive examples, see the Tutorial.

2. Widget Structure

Every widget consists of exactly three files. All three layers have access to the same parameters ($wgparams) and the instance ID ($wgguid).

LayerFileContent-TypeDescription
PHPwidget_name.phptext/htmlServer-side logic and HTML output
CSSwidget_name.csstext/cssStyling with an optional PHP bridge
JSwidget_name.jstext/javascriptClient-side interaction

Variables available in the widget code

VariableTypeDescription
$wgparamsobject|array|stringWidget parameters (parsed from JSON, a semicolon list, or a string)
$widgetparamsobject|array|stringAlias for $wgparams
$wgguidstringUnique instance ID for CSS/JS scoping

PHP layer — example

<?php
if(isset($widgetparams->uid)) $wgguid = $widgetparams->uid;
else $wgguid = "";
if(isset($wgparams)){
    $text = isset($wgparams->text) ? $wgparams->text : "Default text";
    ?>
    <div id="mein_widget<?= $wgguid;?>" class="mein-widget">
        <p><?= $text;?></p>
    </div>
    <?php
}
?>

Output modes

ModeOutput
phpHTML only (evalAt Widget Storm, eval() executes exclusively widget code that authenticated authors have stored in the database — never user input. It is the technical foundation of the PHP-in-CSS bridge and of dynamic widget composition. No user input ever reaches eval(). result)
cssCSS only (evalThe CSS layer is rendered through eval() to enable the PHP-in-CSS bridge. The code comes exclusively from the database — created by authenticated widget authors. Dynamic selectors and instance-specific styling would not be possible without this mechanism. result)
jsJavaScript only (evalThe JS layer also uses eval() for embedded PHP variables (UID scoping, parameters). As with all widget layers: the executed code is author-verified and stored in the database, not user-generated. result)
(empty)<style>CSS</style> PHP <script>JS</script>

3. Parameter System

Parameters are passed to widgets via wgparams. The system supports three formats:

JSON (recommended)

{"text":"Hello World","color":"#ff0000","items":[1,2,3]}

Parsed into a stdClass object. Access via $wgparams->text.

Semicolon-separated

Value1;Value2;Value3

Parsed into an array. Access via $wgparams[0], $wgparams[1], etc.

Simple string

Any arbitrary text

Passed through unchanged as a string.

URL encoding for HTTP requests

wgparams={"text":"Hello","uid":"abc123"}

// In PHP, for URL parameters:
$packurl = http_build_query(['wgparams' => $paramsArray]);

4. PHP-in-CSS/JS Bridge

CSS and JS files can contain embedded PHP code. Because PHP tags are syntactically invalid in CSS/JS, they are wrapped in comments. The system converts them automatically before execution.

Conversion rules

In the source codeBecomes
/*<?php<?php
/*<?=<?=
?>*/?>

CSS example

/*<?php
if(isset($wgparams->uid)) $wgguid = $wgparams->uid;
else $wgguid = "";
?>*/
div#mein_widget/*<?= $wgguid;?>*/ {
    background: rgba(170,210,210,0.08);
    border: 1px solid rgba(170,210,210,0.2);
    padding: 1em;
    border-radius: 0.4em;
}

JS example

/*<?php
if(isset($wgparams->uid)) $wgguid = $wgparams->uid;
else $wgguid = "";
?>*/
jQuery(document).ready(function(){
    jQuery("#mein_widget/*<?= $wgguid;?>*/").on("click", function(){
        jQuery(this).toggleClass("active");
    });
});
The PHP bridge enables instance-specific CSS selectors and JS handlers, so that multiple instances of the same widget can coexist on a single page.

5. Nesting & Markers

Widgets can load other widgets. This is done via markers in the PHP code, which the server resolves recursively.

Marker syntax

##wgstart##widgetname::author::parameter##wgend##
SegmentDescription
widgetnameName of the widget to embed
authorAuthor of the widget
parameterParameters as JSON or a semicolon list

Resolution process

  1. The server finds all ##wgstart##...##wgend## markers in the PHP code
  2. Extracts the name, author, and parameters from the marker
  3. Resolves the nested widget recursively
  4. The nested widget's CSS and JS are appended to the parent widget
  5. PHP is Base64-encoded and executed via intern_script_wall()

UID Scoping & Placeholders

PlaceholderReplacementUsage
##self##widgetname + md5($wgguid)Unique selector per instance
##wgself##widgetname + md5($wgguid)Alias for ##self##
##selfreplace####self##Escape: literal ##self## in the output

6. Availability Levels

LevelAccessBilling
openAll registered usersFree
authenticatedAuthor + users with explicit permissionOptional
paymentAuthor + users with active billingRequired

Developers set the availability at upload time (parameter wgrmode). The level determines who can retrieve the widget through their wgclient — and whether billing is required.

Access control

1. Widget.availability == 'open'       → Access granted
2. Widget.author == RequestUser        → Access granted (author)
3. Permission check                    → Checked against the internal permission table
   - Global permission                 → Applies to all users
   - Specific permission               → Applies to individual users

Widget-level security

Widgets can bring their own security mechanisms — independent of the host system. The wg_demo_todo widget demonstrates this principle: AES-256-encrypted persistence, key-based authentication with brute-force protection, and automatic preflight checks for dependencies and permissions. You can find more details on the widget overview.

7. HTTP Endpoints

wgclient.php — widget delivery (local)

Serves both as an HTTP endpoint and as a PHP include for server-side integration.

ParameterRequiredDescription
wgnameYesWidget name
wgauthorNoWidget author (default: WidgetStormSystem)
wgmodeNoOutput mode: php, css, js, or empty (all)
wgparamsNoWidget parameters (JSON, semicolon list, or string)
wgguidNoInstance ID for scoping

wgcall.php — remote widget delivery

Endpoint for external servers. Requires authentication and encrypts the response.

ParameterRequiredDescription
wgnameYesWidget name (alphanumeric + underscore + hyphen)
wgauthorYesWidget author
wgmodeYesAllowed values: php, css, js, go, c, md
requestuserYesUsername
requestkeyYesAuthentication key (MD5 hash)
wgparamsNoWidget parameters
wgguidNoInstance ID
wgfirstNotrue = no nesting resolution

wgregistration.php — widget upload

Endpoint for uploading new or updated widgets.

ParameterDescription
wgrnameWidget name
wgrparamLayer: php, css, js
wgrcodeEncrypted widget code
wgrmodeAvailability: authenticated, open, payment
wgrrequestuserUsername
wgrrequestkeyAuthentication key
Author isolation: Uploads are bound to the authenticated user. You can only create or update your own widgets — other authors' widgets are protected from being overwritten. When uploading from wgbuilds/ (batch mode), only widgets assigned to your own author account are processed.

wgclientcreator.php — client download

Generates a personalized wgclient.php with embedded credentials. Requires an active session (login via the Station). A new requestkey is generated on every download (key rotation via md5(username + uniqid())).

wghandlercreator.php — handler download

Generates a portable wghandler.php class with an embedded RIJNDAEL-256 implementation (pure PHP via phpseclib3, compatible with PHP 8+), local widget caching, and support for nested widgets.

8. Widget Integration

Local integration (same server)

<!-- CSS in the <head> -->
<link rel="stylesheet"
    href="wgclient.php?wgname=basic&wgauthor=WidgetStormSystem&wgmode=css&wgparams=..."
    type="text/css">

<!-- JavaScript before </body> -->
<script src="wgclient.php?wgname=basic&wgauthor=WidgetStormSystem&wgmode=js&wgparams=..."></script>

<!-- PHP in the <body> -->
<?php
require_once 'wgclient.php';
$wg->get('basic', 'WidgetStormSystem', $params, 'php');
?>

Remote integration (external server)

<?php
// Place wgclient.php and wghandler.php on your own server
require_once 'wgclient.php';

// The credentials are embedded in wgclient.php
$wg->get('basic', 'WidgetStormSystem', $params, 'php');
?>

Execution modes (wgexecutionmode)

The developer uses wgexecutionmode to control whether a widget is rendered locally from the CodeVault or fetched live from the Widget Storm server. The default mode uses the local cache — which means no network latency and maximum loading speed.

ModeBehaviorUse case
(Default)Local CodeVault — load widgets from the cacheProduction: fastest delivery, no server dependency
liveRemote fetch — load and execute the widget live from the serverDevelopment: always the latest version, no local file needed
uploadwidgetsBatch upload — upload local widgets in wgbuilds/Deployment: sync all your own widgets from the local directory
Rendering control: The mode determines where the widget code comes from — the rendering itself always happens server-side via PHP (evaleval() executes the widget code in the server context. The code comes either from the local CodeVault (file system) or from the database — both author-verified sources, no user input.). This gives each widget instance its own parameters and CSS selectors.

9. Encryption

Communication between client and server is encrypted. The system supports two encryption versions per user: RIJNDAEL-256 (the original method, in use since 2008) and AES-256-CBC (the modern standard for new users). Both coexist through a central EncryptionNegotiator that automatically selects the appropriate version per user.

VersionAlgorithmModeStatus
v1_rijndaelRIJNDAEL-256ECBLegacy (since 2008)
v2_aesAES-256-CBCCBC with a random IVStandard for new users

Both directions (server → client and client → server) are encrypted at the application level. Each user has an individual key, which is rotated on every client download.

RIJNDAEL-256 ≠ AES-256. AES uses 128-bit blocks (standardized by NIST); RIJNDAEL-256 uses 256-bit blocks (a related algorithm, but not part of the AES standard).
Historical context: RIJNDAEL-256 was chosen in 2008, when PHP’s mcrypt extension was the standard way to do cryptography and openssl_encrypt() was not yet available. The decision matched the state of the art at the time. Since the modernization to PHP 8.3, phpseclib3 is used as a drop-in replacement for the removed mcrypt extension. You can find detailed background on this in the FAQ.

10. Rate Limiting

EndpointLimitWindowHTTP status when exceeded
wgcall.php120 requests60 seconds429 Too Many Requests
wgregistration.php30 uploads60 seconds429 Too Many Requests

Tracking is done per IP address and endpoint. State files in /tmp/ws-ratelimit/.

11. CodeVault

The CodeVault is the heart of widget delivery. It stores widget code as local files on the client server — which means direct file-system access instead of network round-trips. Widgets load as fast as any other local PHP file, without any dependency on the central Widget Storm server.

Purpose & benefits

PropertyDescription
SpeedLocal file reads instead of HTTP requests — load times in the microsecond range
IndependenceWidgets keep working even when the Widget Storm server is unreachable
RedundancyDual storage: database (server) + file system (client)
Author isolationEach author has their own subdirectory — overwriting other authors' widgets is not possible

Directory structure

wgbuilds/
  ├─ {Author}/
  │   ├─ {widget_name}.php
  │   ├─ {widget_name}.css
  │   └─ {widget_name}.js
  └─ WidgetStormSystem/
      ├─ basic.php
      ├─ basic.css
      ├─ basic.js
      ├─ wg_nav.php
      └─ ...

The directory structure is organized by author. During batch upload (uploadwidgets mode), the wghandler scans the wgbuilds/ directory and automatically uploads changed files to the server — processing only your own widgets. Widgets from other authors remain untouched.

Rendering from the CodeVault

In the default mode, the wgclient reads the widget code directly from wgbuilds/ and executes it locally (evalThe CodeVault code is executed via eval() in the server context. The files come from the authenticated download or your own upload — they are identical to the database original. No external input flows into the execution.). The live mode bypasses the CodeVault and queries the Widget Storm server directly — useful during development, but slower than the local cache.

Design philosophy: The CodeVault is deliberately designed as the primary storage medium for delivery — not as a fallback. Local files are the fastest possible way to deliver widgets, and they make any website with Widget Storm integration resilient against temporary server outages.