1313<?
1414$ docroot ??= ($ _SERVER ['DOCUMENT_ROOT ' ] ?: '/usr/local/emhttp ' );
1515require_once "$ docroot/webGui/include/Helpers.php " ;
16+ require_once "$ docroot/plugins/dynamix/include/PopularDestinations.php " ;
1617
1718// add translations
1819$ _SERVER ['REQUEST_URI ' ] = '' ;
@@ -44,7 +45,7 @@ function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',
4445
4546switch ($ _POST ['mode ' ] ?? $ _GET ['mode ' ] ?? '' ) {
4647case 'upload ' :
47- $ file = validname (htmlspecialchars_decode ( rawurldecode ($ _POST ['file ' ] ?? $ _GET ['file ' ] ?? '' ) ));
48+ $ file = validname (rawurldecode ($ _POST ['file ' ] ?? $ _GET ['file ' ] ?? '' ));
4849 if (!$ file ) die ('stop ' );
4950 $ start = (int )($ _POST ['start ' ] ?? $ _GET ['start ' ] ?? 0 );
5051 $ cancel = (int )($ _POST ['cancel ' ] ?? $ _GET ['cancel ' ] ?? 0 );
@@ -93,7 +94,7 @@ function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',
9394 die ();
9495case 'calc ' :
9596 extract (parse_plugin_cfg ('dynamix ' ,true ));
96- $ source = explode ("\n" ,htmlspecialchars_decode ( rawurldecode ($ _POST ['source ' ]) ));
97+ $ source = explode ("\n" ,rawurldecode ($ _POST ['source ' ] ?? '' ));
9798 [$ null ,$ root ,$ main ,$ rest ] = my_explode ('/ ' ,$ source [0 ],4 );
9899 if ($ root =='mnt ' && in_array ($ main ,['user ' ,'user0 ' ])) {
99100 $ disks = parse_ini_file ('state/disks.ini ' ,true );
@@ -120,8 +121,8 @@ function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',
120121 $ calc = '<div style="text-align:left;margin-left:56px"> ' .implode ('<br> ' ,$ calc ).'</div> ' ;
121122 die ($ calc );
122123case 'home ' :
123- $ source = explode ("\n" ,htmlspecialchars_decode ( rawurldecode ($ _POST ['source ' ]) ));
124- $ target = htmlspecialchars_decode ( rawurldecode ($ _POST ['target ' ]) );
124+ $ source = explode ("\n" ,rawurldecode ($ _POST ['source ' ] ?? '' ));
125+ $ target = rawurldecode ($ _POST ['target ' ] ?? '' );
125126 $ disks = parse_ini_file ('state/disks.ini ' ,true );
126127 $ tag = implode ('| ' ,array_merge (['disk ' ],pools_filter ($ disks )));
127128 $ loc1 = implode (', ' ,array_unique (array_filter (explode (', ' ,preg_replace ("/( $ tag)/ " ,',$1 ' ,exec ("getfattr --no-dereference --absolute-names --only-values -n system.LOCATIONS " .quoted ($ source )." 2>/dev/null " ))))));
@@ -152,8 +153,9 @@ function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',
152153 if ($ file = validname (rawurldecode ($ _POST ['file ' ]))) file_put_contents ($ file ,rawurldecode ($ _POST ['data ' ]));
153154 die ();
154155case 'stop ' :
155- $ file = htmlspecialchars_decode (rawurldecode ($ _POST ['file ' ]));
156- delete_file ("/var/tmp/ $ file.tmp " );
156+ // Prevent path traversal: only use basename (no directory components)
157+ $ file = basename (rawurldecode ($ _POST ['file ' ] ?? '' ));
158+ if ($ file !== '' ) delete_file ("/var/tmp/ $ file.tmp " );
157159 die ();
158160case 'start ' :
159161 $ active = '/var/tmp/file.manager.active ' ;
@@ -163,6 +165,30 @@ function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',
163165 // read first JSON line from jobs file and write to active
164166 $ lines = file ($ jobs , FILE_IGNORE_NEW_LINES );
165167 if (!empty ($ lines )) {
168+ // Skip invalid JSON entries (scan once, slice once)
169+ $ skipped = 0 ;
170+ $ data = null ;
171+ for ($ i = 0 , $ n = count ($ lines ); $ i < $ n ; $ i ++) {
172+ $ data = json_decode ($ lines [$ i ], true );
173+ if ($ data ) break ;
174+ $ skipped ++;
175+ }
176+ if ($ skipped > 0 ) {
177+ exec ('logger -t webGUI "Warning: Skipped ' .$ skipped .' invalid JSON entr ' .($ skipped ===1 ?'y ' :'ies ' ).' in file manager job queue" ' );
178+ $ lines = array_slice ($ lines , $ skipped );
179+ }
180+
181+ if (empty ($ lines )) {
182+ // No valid JSON entries found
183+ delete_file ($ jobs );
184+ die ('0 ' );
185+ }
186+
187+ // Update popular destinations when dequeuing a job
188+ if (in_array ((int )($ data ['action ' ] ?? 0 ), [3 , 4 , 8 , 9 ]) && !empty ($ data ['target ' ] ?? '' )) {
189+ updatePopularDestinations ($ data ['target ' ]);
190+ }
191+
166192 file_put_contents ($ active , $ lines [0 ]);
167193 // remove first line from jobs file
168194 array_shift ($ lines );
@@ -180,9 +206,13 @@ function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',
180206 $ jobs = '/var/tmp/file.manager.jobs ' ;
181207 $ undo = '0 ' ;
182208 if (file_exists ($ jobs )) {
183- $ rows = array_reverse ( explode (', ' ,$ _POST ['row ' ]) );
209+ $ rows = explode (', ' , $ _POST ['row ' ] ?? '' );
184210 $ lines = file ($ jobs , FILE_IGNORE_NEW_LINES );
185211 foreach ($ rows as $ row ) {
212+ $ row = trim ($ row );
213+ if ($ row === '' || !ctype_digit ($ row )) continue ;
214+ $ row = (int )$ row ;
215+ if ($ row < 1 ) continue ;
186216 $ line_number = $ row - 1 ; // Convert 1-based job number to 0-based array index
187217 if (isset ($ lines [$ line_number ])) {
188218 unset($ lines [$ line_number ]);
@@ -205,10 +235,10 @@ function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',
205235 $ active = '/var/tmp/file.manager.active ' ;
206236 $ jobs = '/var/tmp/file.manager.jobs ' ;
207237 $ data = [
208- 'action ' => $ _POST ['action ' ] ?? '' ,
238+ 'action ' => ( int )( $ _POST ['action ' ] ?? 0 ) ,
209239 'title ' => rawurldecode ($ _POST ['title ' ] ?? '' ),
210- 'source ' => htmlspecialchars_decode ( rawurldecode ($ _POST ['source ' ] ?? '' ) ),
211- 'target ' => htmlspecialchars_decode ( rawurldecode ($ _POST ['target ' ] ?? '' ) ),
240+ 'source ' => rawurldecode ($ _POST ['source ' ] ?? '' ),
241+ 'target ' => rawurldecode ($ _POST ['target ' ] ?? '' ),
212242 'H ' => empty ($ _POST ['hdlink ' ]) ? '' : 'H ' ,
213243 'sparse ' => empty ($ _POST ['sparse ' ]) ? '' : '--sparse ' ,
214244 'exist ' => empty ($ _POST ['exist ' ]) ? '--ignore-existing ' : '' ,
@@ -221,7 +251,13 @@ function quoted($name) {return is_array($name) ? implode(' ',array_map('escape',
221251 } else {
222252 // start operation
223253 file_put_contents ($ active , json_encode ($ data ));
254+ // Update popular destinations only when an operation actually starts
255+ // Action types: 3=copy folder, 4=move folder, 8=copy file, 9=move file
256+ if (in_array ((int )$ data ['action ' ], [3 , 4 , 8 , 9 ]) && !empty ($ data ['target ' ])) {
257+ updatePopularDestinations ($ data ['target ' ]);
258+ }
224259 }
260+
225261 die ();
226262}
227263?>
0 commit comments