Skip to content

Commit b946b20

Browse files
committed
Avoid pass-by-reference issues in config parsing leading to duplicated responses; ref pterodactyl#2511
1 parent 63f8f53 commit b946b20

File tree

1 file changed

+29
-36
lines changed

1 file changed

+29
-36
lines changed

app/Services/Eggs/EggConfigurationService.php

Lines changed: 29 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -104,47 +104,33 @@ protected function replacePlaceholders(Server $server, object $configs)
104104
// can property map the egg placeholders to values.
105105
$structure = $this->configurationStructureService->handle($server, true);
106106

107-
foreach ($configs as $file => &$data) {
108-
$this->iterate($data->find, $structure);
109-
}
110-
111107
$response = [];
112108
// Normalize the output of the configuration for the new Wings Daemon to more
113109
// easily ingest, as well as make things more flexible down the road.
114110
foreach ($configs as $file => $data) {
115-
$append = ['file' => $file, 'replace' => []];
116-
117-
/** @noinspection PhpParameterByRefIsNotUsedAsReferenceInspection */
118-
// I like to think I understand PHP pretty well, but if you don't pass $value
119-
// by reference here, you'll end up with a resursive array loop if the config
120-
// file has two replacements that reference the same item in the configuration
121-
// array for the server.
122-
foreach ($data as $key => &$value) {
123-
if ($key !== 'find') {
124-
$append[$key] = $value;
125-
continue;
126-
}
127-
128-
foreach ($value as $find => $replace) {
129-
if (is_object($replace)) {
130-
foreach ($replace as $match => $replaceWith) {
131-
$append['replace'][] = [
132-
'match' => $find,
133-
'if_value' => $match,
134-
'replace_with' => $replaceWith,
135-
];
136-
}
137-
138-
continue;
111+
$append = array_merge((array)$data, ['file' => $file, 'replace' => []]);
112+
113+
foreach ($this->iterate($data->find, $structure) as $find => $replace) {
114+
if (is_object($replace)) {
115+
foreach ($replace as $match => $replaceWith) {
116+
$append['replace'][] = [
117+
'match' => $find,
118+
'if_value' => $match,
119+
'replace_with' => $replaceWith,
120+
];
139121
}
140122

141-
$append['replace'][] = [
142-
'match' => $find,
143-
'replace_with' => $replace,
144-
];
123+
continue;
145124
}
125+
126+
$append['replace'][] = [
127+
'match' => $find,
128+
'replace_with' => $replace,
129+
];
146130
}
147131

132+
unset($append['find']);
133+
148134
$response[] = $append;
149135
}
150136

@@ -248,21 +234,28 @@ protected function matchAndReplaceKeys($value, array $structure)
248234
*
249235
* @param mixed $data
250236
* @param array $structure
237+
* @return mixed
251238
*/
252-
private function iterate(&$data, array $structure)
239+
private function iterate($data, array $structure)
253240
{
254241
if (! is_iterable($data) && ! is_object($data)) {
255-
return;
242+
return $data;
256243
}
257244

258-
foreach ($data as &$value) {
245+
// Remember, in PHP objects are always passed by reference, so if we do not clone this object
246+
// instance we'll end up making modifications to the object outside the scope of this function
247+
// which leads to some fun behavior in the parser.
248+
$clone = clone $data;
249+
foreach ($clone as $key => &$value) {
259250
if (is_iterable($value) || is_object($value)) {
260-
$this->iterate($value, $structure);
251+
$value = $this->iterate($value, $structure);
261252

262253
continue;
263254
}
264255

265256
$value = $this->matchAndReplaceKeys($value, $structure);
266257
}
258+
259+
return $clone;
267260
}
268261
}

0 commit comments

Comments
 (0)