1. Security: Input & Output
Always clean input and escape output.
- Input: Use
required_param()andoptional_param()with the correctPARAM_*type. - Output: Use
s(),format_string(), orformat_text().
$id = required_param('id', PARAM_INT);
$text = optional_param('text', '', PARAM_TEXT);
echo s($text); // Escapes HTML entities
2. Caching (MUC)
The Moodle Universal Cache (MUC) is critical for performance.
- Request Cache: Stores data for the duration of a single request (static variables).
- Session Cache: Stores data for the user's session.
- Application Cache: Shared across all users (e.g., course settings). Use Redis for this in production.
3. Performance Tips
- Session Handling: Use Redis for sessions instead of the database or files.
- Cron: Ensure the cron job runs every minute.
- Database: Use a read replica for heavy reporting queries.
4. Capability Checks
Never assume a user can do something. Always check permissions.
$context = context_course::instance($course->id);
// Check if user has capability
if (!has_capability('mod/quiz:view', $context)) {
print_error('nopermission');
}
// Or enforce it (stops execution if false)
require_capability('mod/quiz:view', $context);
5. SQL Injection Prevention
Moodle's DML API handles parameter binding automatically. Never concatenate variables into SQL strings.
// BAD (Vulnerable)
$DB->get_records_sql("SELECT * FROM {user} WHERE username = '$name'");
// GOOD (Safe)
$DB->get_records_sql("SELECT * FROM {user} WHERE username = ?", [$name]);
// OR
$DB->get_records_sql("SELECT * FROM {user} WHERE username = :name", ['name' => $name]);
6. CSRF Protection (Sesskey)
Cross-Site Request Forgery (CSRF) is prevented using a session key (sesskey).
- Forms: Moodle forms automatically include a hidden
sesskeyfield. - Manual Links: Append
?sesskey=...to URLs that perform actions (e.g., delete). - Validation: The receiving script must call
require_sesskey()(orconfirm_sesskey()) to verify the token.
// In a form
$mform->addElement('hidden', 'sesskey', sesskey());
// In a script processing a POST request
require_sesskey();
7. Session Locking
To prevent race conditions, Moodle locks the user's session while a request is processing. This means a user cannot load two pages simultaneously (the second one waits).
- Problem: Long-running reports block the user's interface.
- Solution: Release the session lock early if you don't need to write to the session anymore.
\core\session\manager::write_close();
// Now perform long-running task...