Skip to content

Commit b67b173

Browse files
committed
docs(settings): recommend default.cfg for plugin defaults
Replace manual $defaults array + array_merge pattern with the built-in parse_plugin_cfg() merging via default.cfg. Removes redundant "create defaults on install" PLG/script/PHP patterns in favor of shipping default.cfg in the plugin package. Thanks @Squidly271 in issue #2
1 parent a6c7d1e commit b67b173

1 file changed

Lines changed: 89 additions & 97 deletions

File tree

docs/core/plugin-settings-storage.md

Lines changed: 89 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -97,30 +97,32 @@ if (file_exists($path)) {
9797

9898
## Reading Configuration
9999

100-
### With Defaults (Recommended Pattern)
100+
### With `default.cfg` (Recommended Pattern)
101101

102102
```php
103103
<?
104-
// Define defaults
105-
$defaults = [
106-
'enabled' => 'no',
107-
'interval' => '60',
108-
'path' => '/mnt/user/appdata',
109-
'notify_level' => 'normal',
110-
'log_enabled' => 'no',
111-
'max_log_size' => '1048576'
112-
];
113-
114-
// Read config and merge with defaults
104+
// Keep defaults in:
105+
// /usr/local/emhttp/plugins/yourplugin/default.cfg
106+
// parse_plugin_cfg() merges defaults with user config automatically.
115107
$cfg = parse_plugin_cfg("yourplugin");
116-
$settings = array_merge($defaults, $cfg);
117108

118-
// Now $settings always has all keys
119-
$enabled = $settings['enabled'];
120-
$interval = $settings['interval'];
109+
// $cfg already includes defaults for any missing keys.
110+
$enabled = $cfg['enabled'] === 'yes';
111+
$interval = intval($cfg['interval']);
121112
?>
122113
```
123114

115+
```ini
116+
# /usr/local/emhttp/plugins/yourplugin/default.cfg
117+
enabled="no"
118+
interval="60"
119+
path="/mnt/user/appdata"
120+
notify_level="normal"
121+
```
122+
123+
{: .note }
124+
> Keep defaults in `default.cfg` (under `/usr/local/emhttp/plugins/<plugin>/`) instead of recreating default values in each PHP script.
125+
124126
### Type-Safe Access
125127

126128
```php
@@ -143,29 +145,37 @@ if (!is_dir($path)) {
143145

144146
## Writing Configuration
145147

148+
When handling form submissions or AJAX writes, validate the CSRF token before saving settings. See [CSRF Tokens](csrf-tokens.md) for the full pattern and background.
149+
146150
### Basic Write Pattern
147151

148152
```php
149153
<?
150154
// /plugins/yourplugin/update.php
151155

156+
function save_plugin_cfg($plugin, $settings) {
157+
$cfg_file = "/boot/config/plugins/$plugin/$plugin.cfg";
158+
$config = "";
159+
160+
foreach ($settings as $key => $value) {
161+
$config .= "$key=\"$value\"\n";
162+
}
163+
164+
return file_put_contents($cfg_file, $config) !== false;
165+
}
166+
152167
// Validate CSRF
153168
$var = parse_ini_file('/var/local/emhttp/var.ini');
154169
if ($_POST['csrf_token'] !== $var['csrf_token']) {
155170
die("Invalid CSRF token");
156171
}
157172

158-
// Define config file path
159-
$cfg_file = "/boot/config/plugins/yourplugin/yourplugin.cfg";
160-
161-
// Build configuration content
162-
$config = "";
163-
$config .= "enabled=\"{$_POST['enabled']}\"\n";
164-
$config .= "interval=\"{$_POST['interval']}\"\n";
165-
$config .= "path=\"{$_POST['path']}\"\n";
166-
167-
// Write to file
168-
file_put_contents($cfg_file, $config);
173+
// Use the helper
174+
save_plugin_cfg("yourplugin", [
175+
'enabled' => $_POST['enabled'],
176+
'interval' => $_POST['interval'],
177+
'path' => $_POST['path']
178+
]);
169179
?>
170180
```
171181

@@ -175,11 +185,6 @@ file_put_contents($cfg_file, $config);
175185
<?
176186
// /plugins/yourplugin/update.php
177187

178-
$var = parse_ini_file('/var/local/emhttp/var.ini');
179-
if ($_POST['csrf_token'] !== $var['csrf_token']) {
180-
die("Invalid CSRF token");
181-
}
182-
183188
/**
184189
* Escape value for INI file
185190
*/
@@ -190,30 +195,43 @@ function escapeIniValue($value) {
190195
return $value;
191196
}
192197

193-
$cfg_file = "/boot/config/plugins/yourplugin/yourplugin.cfg";
198+
function save_plugin_cfg($plugin, $settings) {
199+
$cfg_file = "/boot/config/plugins/$plugin/$plugin.cfg";
194200

195-
// Sanitize and validate inputs
196-
$enabled = in_array($_POST['enabled'], ['yes', 'no']) ? $_POST['enabled'] : 'no';
197-
$interval = max(1, min(3600, intval($_POST['interval']))); // 1-3600 range
198-
$path = trim($_POST['path']);
201+
$config = "";
202+
foreach ($settings as $key => $value) {
203+
$key = preg_replace('/[^a-zA-Z0-9_]/', '', $key);
204+
$config .= "$key=\"" . escapeIniValue($value) . "\"\n";
205+
}
199206

200-
// Build config
201-
$config = "";
202-
$config .= "enabled=\"" . escapeIniValue($enabled) . "\"\n";
203-
$config .= "interval=\"" . escapeIniValue($interval) . "\"\n";
204-
$config .= "path=\"" . escapeIniValue($path) . "\"\n";
207+
$dir = dirname($cfg_file);
208+
if (!is_dir($dir)) {
209+
mkdir($dir, 0755, true);
210+
}
205211

206-
// Ensure directory exists
207-
$dir = dirname($cfg_file);
208-
if (!is_dir($dir)) {
209-
mkdir($dir, 0755, true);
212+
$temp_file = $cfg_file . '.tmp';
213+
if (file_put_contents($temp_file, $config) !== false) {
214+
return rename($temp_file, $cfg_file);
215+
}
216+
217+
return false;
210218
}
211219

212-
// Write atomically (write to temp, then rename)
213-
$temp_file = $cfg_file . '.tmp';
214-
if (file_put_contents($temp_file, $config) !== false) {
215-
rename($temp_file, $cfg_file);
220+
$var = parse_ini_file('/var/local/emhttp/var.ini');
221+
if ($_POST['csrf_token'] !== $var['csrf_token']) {
222+
die("Invalid CSRF token");
216223
}
224+
225+
// Sanitize and validate inputs
226+
$enabled = in_array($_POST['enabled'], ['yes', 'no']) ? $_POST['enabled'] : 'no';
227+
$interval = max(1, min(3600, intval($_POST['interval']))); // 1-3600 range
228+
$path = trim($_POST['path']);
229+
230+
save_plugin_cfg("yourplugin", [
231+
'enabled' => $enabled,
232+
'interval' => $interval,
233+
'path' => $path
234+
]);
217235
?>
218236
```
219237

@@ -264,66 +282,40 @@ save_plugin_cfg("yourplugin", [
264282
?>
265283
```
266284

267-
## Default File Creation
285+
## Default File Strategy
268286

269-
### Creating Defaults on Install (PLG)
287+
Use two files with clear responsibilities:
270288

271-
```xml
272-
<!-- In your .plg file -->
273-
<FILE Name="/boot/config/plugins/yourplugin/yourplugin.cfg">
274-
<INLINE>
275-
enabled="no"
276-
interval="60"
277-
path="/mnt/user/appdata"
278-
notify_level="normal"
279-
</INLINE>
280-
</FILE>
281-
```
289+
- `/usr/local/emhttp/plugins/yourplugin/default.cfg` for shipped defaults
290+
- `/boot/config/plugins/yourplugin/yourplugin.cfg` for user overrides
282291

283-
{: .note }
284-
> This creates the file only if it doesn't exist. Existing files are preserved on plugin updates.
292+
`parse_plugin_cfg("yourplugin")` handles merging, so you do not need to rewrite defaults at runtime.
293+
294+
### Shipping `default.cfg` in Your Package
285295

286-
### Creating Defaults via Script
296+
Install `default.cfg` as part of your plugin package so it is available in `/usr/local/emhttp/plugins/yourplugin/`.
287297

288-
```xml
289-
<FILE Run="/bin/bash">
290-
<INLINE>
291-
CFG="/boot/config/plugins/yourplugin/yourplugin.cfg"
292-
if [ ! -f "$CFG" ]; then
293-
mkdir -p /boot/config/plugins/yourplugin
294-
cat > "$CFG" << 'EOF'
298+
```ini
299+
# /usr/local/emhttp/plugins/yourplugin/default.cfg
295300
enabled="no"
296301
interval="60"
297302
path="/mnt/user/appdata"
298-
EOF
299-
fi
300-
</INLINE>
301-
</FILE>
303+
notify_level="normal"
302304
```
303305

304-
### Runtime Default Creation (PHP)
306+
### Writing Only User Changes
307+
308+
When saving settings, write only values the user changed into `yourplugin.cfg`.
305309

306310
```php
307311
<?
308-
$cfg_file = "/boot/config/plugins/yourplugin/yourplugin.cfg";
312+
$cfg = parse_plugin_cfg("yourplugin");
309313

310-
// Create default config if it doesn't exist
311-
if (!file_exists($cfg_file)) {
312-
$defaults = <<<EOT
313-
enabled="no"
314-
interval="60"
315-
path="/mnt/user/appdata"
316-
notify_level="normal"
317-
EOT;
318-
319-
$dir = dirname($cfg_file);
320-
if (!is_dir($dir)) {
321-
mkdir($dir, 0755, true);
322-
}
323-
file_put_contents($cfg_file, $defaults);
324-
}
314+
// Update only user-editable values
315+
$cfg['enabled'] = $_POST['enabled'];
316+
$cfg['interval'] = strval(max(1, min(3600, intval($_POST['interval']))));
325317

326-
$cfg = parse_plugin_cfg("yourplugin");
318+
save_plugin_cfg("yourplugin", $cfg);
327319
?>
328320
```
329321

@@ -446,14 +438,14 @@ $email_notify = $cfg['notifications']['email'];
446438

447439
## Best Practices
448440

449-
1. **Always provide defaults** - Never assume a setting exists
441+
1. **Use `default.cfg` for defaults** - Let `parse_plugin_cfg()` merge defaults and user overrides
450442
2. **Validate before writing** - Sanitize all user input
451443
3. **Use atomic writes** - Write to temp file, then rename
452444
4. **Escape values properly** - Handle quotes and special characters
453445
5. **Version your config format** - Track schema changes for migrations
454446
6. **Backup before migration** - Preserve user settings when upgrading
455447
7. **Use consistent naming** - `plugin.cfg` matches plugin name
456-
8. **Document settings** - Comment your default configuration
448+
8. **Document settings** - Keep comments and rationale in `default.cfg`
457449

458450
## Related Topics
459451

0 commit comments

Comments
 (0)