CMS Made Simple™ Developer Resources
Securing (Sanitizing) Input
Input sanitization is the process of cleaning data before you use it — removing or neutralizing anything that shouldn't be there. While validation checks whether data is correct, sanitization makes data safe.
The Input Flow
Every piece of user input should pass through this pipeline:
- Register — declare expected parameters and their types (frontend only).
- Sanitize — clean the data (trim, cast, strip).
- Validate — check that the cleaned data meets your requirements.
- Use — pass the clean, validated data to your model or database.
Frontend Parameter Registration
CMSMS provides automatic sanitization for frontend parameters through SetParameterType(). This is the first line of defense — unregistered parameters are stripped entirely:
public function InitializeFrontend()
{
$this->SetParameterType('hid', CLEAN_INT);
$this->SetParameterType('page', CLEAN_INT);
$this->SetParameterType('search', CLEAN_STRING);
$this->SetParameterType('detailpage', CLEAN_STRING);
}
Cleaning constants
| Constant | Effect |
|---|---|
CLEAN_INT |
Casts to integer |
CLEAN_FLOAT |
Casts to float |
CLEAN_STRING |
Strips tags and trims whitespace |
CLEAN_NONE |
No cleaning — use with caution |
Note: Admin action parameters are not filtered through
SetParameterType(). You must sanitize them manually in your action files.
Manual Sanitization in Actions
In admin actions (and as a second pass in frontend actions), sanitize input explicitly:
Strings
// Trim whitespace
$name = trim($params['name'] ?? '');
// Strip HTML tags from plain-text fields
$name = strip_tags(trim($params['name'] ?? ''));
Integers
// Cast to integer
$id = (int) ($params['hid'] ?? 0);
// Ensure positive
$page = max(1, (int) ($params['page'] ?? 1));
Booleans
// Use CMSMS utility — handles 'yes', 'true', '1', 'on', etc.
$published = cms_to_bool($params['published'] ?? false);
Dates
// Convert to unix timestamp
$the_date = strtotime($params['the_date'] ?? '');
if (!$the_date) {
// Invalid date — handle the error
}
Rich text (WYSIWYG content)
Fields edited with a WYSIWYG editor intentionally contain HTML. Do not strip all tags, but do sanitize to remove dangerous elements:
// Allow safe HTML, remove scripts and event handlers
$description = $params['description'] ?? '';
// At minimum, remove script tags
$description = preg_replace('/<script\b[^>]*>(.*?)<\/script>/is', '', $description);
Note: WYSIWYG editors like MicroTiny or TinyMCE perform their own sanitization, but you should not rely on client-side filtering alone. Always sanitize on the server.
Using CMSMSExt for Input Sanitization
The CMSMSExt module provides the xt_param class — a type-safe parameter extraction utility that replaces all of the manual sanitization above with clean one-liners. Each method handles defaults, null-safety, and appropriate filtering internally.
// Integers
$id = \xt_param::get_int($params, 'hid', 0);
$page = \xt_param::get_int($params, 'page', 1);
// Strings (strips tags, filters special chars)
$name = \xt_param::get_string($params, 'name', '');
// Booleans (handles 'yes', 'true', '1', 'on', etc.)
$published = \xt_param::get_bool($params, 'published', false);
// Floats
$price = \xt_param::get_float($params, 'price', 0.0);
// Dates (returns unix timestamp or default)
$the_date = \xt_param::get_date($params, 'the_date');
// Rich text / HTML (sanitized via htmLawed)
$description = \xt_param::get_html($params, 'description', '');
// Arrays of strings
$tags = \xt_param::get_string_array($params, 'tags', []);
This is the recommended approach when your module already depends on CMSMSExt. It eliminates repetitive sanitization boilerplate and ensures consistent filtering across your codebase.
SQL Injection Prevention
The most critical form of input sanitization is preventing SQL injection. Always use parameterized queries:
// SAFE — parameterized query
$db = \cms_utils::get_db();
$sql = 'SELECT * FROM ' . CMS_DB_PREFIX . 'mod_holidays WHERE id = ?';
$row = $db->GetRow($sql, [(int) $params['hid']]);
// SAFE — multiple parameters
$sql = 'INSERT INTO ' . CMS_DB_PREFIX . 'mod_holidays (name, the_date) VALUES (?, ?)';
$db->Execute($sql, [$name, $the_date]);
// DANGEROUS — never do this
$sql = "SELECT * FROM " . CMS_DB_PREFIX . "mod_holidays WHERE id = " . $params['hid'];
$row = $db->GetRow($sql);
The ? placeholders are replaced by the database abstraction layer, which properly quotes and escapes the values based on their data type.
File Upload Sanitization
If your module accepts file uploads:
- Check the file extension against a whitelist of allowed types.
- Check the MIME type — do not trust the extension alone.
- Limit file size.
- Generate a safe filename — never use the original filename directly.
- Store uploads outside the module directory (use the CMSMS uploads path).
$allowed_extensions = ['jpg', 'jpeg', 'png', 'gif', 'pdf'];
$ext = strtolower(pathinfo($_FILES['upload']['name'], PATHINFO_EXTENSION));
if (!in_array($ext, $allowed_extensions, true)) {
$this->SetError($this->Lang('error_invalid_file_type'));
$this->RedirectToAdminTab();
}
// Generate a safe filename
$safe_name = uniqid('holiday_') . '.' . $ext;
$config = \cms_config::get_instance();
$dest = $config['uploads_path'] . DIRECTORY_SEPARATOR . 'holidays' . DIRECTORY_SEPARATOR . $safe_name;
move_uploaded_file($_FILES['upload']['tmp_name'], $dest);
Summary: Sanitize by Data Type
| Data type | Manual | CMSMSExt |
|---|---|---|
| Integer | (int) cast |
xt_param::get_int() |
| Float | (float) cast |
xt_param::get_float() |
| Boolean | cms_to_bool() |
xt_param::get_bool() |
| Plain text string | trim(), strip_tags() |
xt_param::get_string() |
| Rich text (HTML) | Remove <script> tags and event handlers |
xt_param::get_html() |
| Date | strtotime() with validation |
xt_param::get_date() |
| File upload | Whitelist extension, check MIME, generate safe filename | — |
| SQL values | Parameterized queries (? placeholders) |
— |
Next Steps
This completes the Module Security chapter. Continue to Events to learn how modules communicate with each other and the CMSMS core through the event system.
