This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | if (! defined('sugarEntry') || ! sugarEntry) |
||
3 | die('Not A Valid Entry Point'); |
||
4 | /********************************************************************************* |
||
5 | * SugarCRM Community Edition is a customer relationship management program developed by |
||
6 | * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc. |
||
7 | |||
8 | * SuiteCRM is an extension to SugarCRM Community Edition developed by Salesagility Ltd. |
||
9 | * Copyright (C) 2011 - 2014 Salesagility Ltd. |
||
10 | * |
||
11 | * This program is free software; you can redistribute it and/or modify it under |
||
12 | * the terms of the GNU Affero General Public License version 3 as published by the |
||
13 | * Free Software Foundation with the addition of the following permission added |
||
14 | * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK |
||
15 | * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY |
||
16 | * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS. |
||
17 | * |
||
18 | * This program is distributed in the hope that it will be useful, but WITHOUT |
||
19 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS |
||
20 | * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more |
||
21 | * details. |
||
22 | * |
||
23 | * You should have received a copy of the GNU Affero General Public License along with |
||
24 | * this program; if not, see http://www.gnu.org/licenses or write to the Free |
||
25 | * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
||
26 | * 02110-1301 USA. |
||
27 | * |
||
28 | * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road, |
||
29 | * SW2-130, Cupertino, CA 95014, USA. or at email address [email protected]. |
||
30 | * |
||
31 | * The interactive user interfaces in modified source and object code versions |
||
32 | * of this program must display Appropriate Legal Notices, as required under |
||
33 | * Section 5 of the GNU Affero General Public License version 3. |
||
34 | * |
||
35 | * In accordance with Section 7(b) of the GNU Affero General Public License version 3, |
||
36 | * these Appropriate Legal Notices must retain the display of the "Powered by |
||
37 | * SugarCRM" logo and "Supercharged by SuiteCRM" logo. If the display of the logos is not |
||
38 | * reasonably feasible for technical reasons, the Appropriate Legal Notices must |
||
39 | * display the words "Powered by SugarCRM" and "Supercharged by SuiteCRM". |
||
40 | ********************************************************************************/ |
||
41 | |||
42 | |||
43 | require_once ('modules/ModuleBuilder/parsers/ModuleBuilderParser.php'); |
||
44 | |||
45 | class ParserModifyLayoutView extends ModuleBuilderParser |
||
46 | { |
||
47 | |||
48 | var $maxColumns; // number of columns in this layout |
||
49 | var $usingWorkingFile = false; // if a working file exists (used by view.edit.php among others to determine the title for the layout edit panel) |
||
50 | var $language_module; // set to module name for studio, passed to the smarty template and used by sugar_translate |
||
51 | var $_sourceFile; // private - the source of the layout defn |
||
52 | var $_customFile; // private |
||
53 | var $_workingFile; // private |
||
54 | var $_originalFile; //private |
||
55 | var $_moduleVariable; // private - if set, contains the name of the variable containing the module name in the $viewdef file |
||
56 | var $_module; // private |
||
57 | var $_view; // private |
||
58 | var $_viewdefs; // private |
||
59 | var $_fieldDefs; // private |
||
60 | |||
61 | |||
62 | /** |
||
63 | * Constructor |
||
64 | */ |
||
65 | function init ($module, $view, $submittedLayout = false) |
||
66 | { |
||
67 | $this->_view = ucfirst($view); |
||
68 | $this->_module = $module; |
||
69 | $this->language_module = $module; |
||
70 | |||
71 | $this->_baseDirectory = "modules/{$module}/metadata/"; |
||
72 | $file = $this->_baseDirectory . strtolower($view) . "defs.php"; |
||
73 | $this->_customFile = "custom/" . $file; |
||
74 | $this->_workingFile = "custom/working/" . $file; |
||
75 | |||
76 | $this->_sourceView = $this->_view; |
||
77 | $this->_originalFile = $file ; |
||
78 | $this->_sourceFile = $file; |
||
79 | if (is_file($this->_workingFile)) |
||
80 | { |
||
81 | $this->_sourceFile = $this->_workingFile; |
||
82 | $this->usingWorkingFile = true; |
||
83 | } |
||
84 | else if (is_file($this->_customFile)) |
||
85 | { |
||
86 | $this->_sourceFile = $this->_customFile; |
||
87 | } |
||
88 | else if (! is_file($this->_sourceFile)) |
||
89 | { |
||
90 | // if we don't have ANY defined metadata then improvise as best we can |
||
91 | if (strtolower($this->_view) == 'quickcreate') |
||
92 | { |
||
93 | // special handling for quickcreates - base the quickcreate on the editview if no quickcreatedef exists |
||
94 | $this->_sourceFile = $this->_baseDirectory."editviewdefs.php"; |
||
95 | if (is_file("custom/" . $this->_sourceFile)) |
||
96 | { |
||
97 | $this->_sourceFile = "custom/" . $this->_sourceFile; |
||
98 | } |
||
99 | $this->_sourceView = 'EditView'; |
||
100 | } |
||
101 | else |
||
102 | { |
||
103 | $this->_fatalError('parser.modifylayout.php->init(): no metadata for '.$this->_module.' '.$this->_view); |
||
104 | } |
||
105 | } |
||
106 | |||
107 | // get the fieldDefs from the bean |
||
108 | $class = $GLOBALS ['beanList'] [$module]; |
||
109 | require_once ($GLOBALS ['beanFiles'] [$class]); |
||
110 | $bean = new $class(); |
||
111 | $this->_fieldDefs = & $bean->field_defs; |
||
112 | |||
113 | $this->loadModule($this->_module, $this->_sourceView); |
||
114 | $this->_viewdefs ['panels'] = $this->_parseData($this->_viewdefs['panels']); // put into a canonical format |
||
115 | $this->maxColumns = $this->_viewdefs ['templateMeta'] ['maxColumns']; |
||
116 | |||
117 | if ($submittedLayout) |
||
118 | { |
||
119 | // replace the definitions with the new submitted layout |
||
120 | $this->_loadLayoutFromRequest(); |
||
121 | } else |
||
122 | { |
||
123 | $this->_padFields(); // destined for a View, so we want to add in (empty) fields |
||
124 | } |
||
125 | // $GLOBALS['log']->debug($this->_viewdefs['panels']); |
||
126 | |||
127 | } |
||
128 | |||
129 | function getAvailableFields () |
||
130 | { |
||
131 | // Available fields are those that are in the Model and the original layout definition, but not already shown in the View |
||
132 | // So, because the formats of the two are different we brute force loop through View and unset the fields we find in a copy of Model |
||
133 | $availableFields = $this->_getModelFields(); |
||
134 | $GLOBALS['log']->debug( get_class($this)."->getAvailableFields(): _getModelFields returns: ".implode(",",array_keys($availableFields))); |
||
135 | if (! empty($this->_viewdefs)) |
||
136 | { |
||
137 | foreach ($this->_viewdefs ['panels'] as $panel) |
||
138 | { |
||
139 | foreach ($panel as $row) |
||
140 | { |
||
141 | foreach ($row as $fieldArray) |
||
142 | { // fieldArray is an array('name'=>name,'label'=>label) |
||
143 | if (isset($fieldArray ['name'])) |
||
144 | { |
||
145 | unset($availableFields [$fieldArray ['name']]); |
||
146 | $GLOBALS['log']->debug( get_class($this)."->getAvailableFields(): removing ".$fieldArray ['name'] ); |
||
147 | } |
||
148 | } |
||
149 | } |
||
150 | } |
||
151 | } |
||
152 | return $availableFields; |
||
153 | } |
||
154 | |||
155 | function getLayout () |
||
156 | { |
||
157 | return $this->_viewdefs ['panels']; |
||
158 | } |
||
159 | |||
160 | function writeWorkingFile () |
||
161 | { |
||
162 | $this->_writeToFile($this->_workingFile,$this->_view,$this->_module,$this->_viewdefs,$this->_variables); |
||
163 | } |
||
164 | |||
165 | function handleSave () |
||
166 | { |
||
167 | $this->_writeToFile($this->_customFile,$this->_view,$this->_module,$this->_viewdefs,$this->_variables); |
||
168 | // now clear the cache so that the results are immediately visible |
||
169 | include_once('include/TemplateHandler/TemplateHandler.php'); |
||
170 | if (strtolower($this->_view) == 'quickcreate') |
||
171 | { |
||
172 | TemplateHandler::clearCache($this->_module,"form_SubPanelQuickCreate_{$this->_module}.tpl"); |
||
173 | TemplateHandler::clearCache($this->_module,"form_DCQuickCreate_{$this->_module}.tpl"); |
||
174 | } |
||
175 | else |
||
176 | { |
||
177 | TemplateHandler::clearCache($this->_module,"{$this->_view}.tpl"); |
||
178 | } |
||
179 | |||
180 | } |
||
181 | |||
182 | function loadModule ($module, $view) |
||
183 | { |
||
184 | $this->_viewdefs = array(); |
||
185 | $viewdefs = null; |
||
186 | |||
187 | $loaded = $this->_loadFromFile($view,$this->_sourceFile,$module); |
||
188 | $this->_viewdefs = $loaded['viewdefs'][$module][$view]; |
||
189 | $this->_variables = $loaded['variables']; |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * Load the canonical panel layout from the submitted form |
||
194 | * |
||
195 | */ |
||
196 | function _loadLayoutFromRequest () |
||
197 | { |
||
198 | |||
199 | $i = 1; |
||
200 | // set up the map of panel# (as provided in the _REQUEST) to panel ID (as used in $this->_viewdefs['panels']) |
||
201 | foreach ($this->_viewdefs ['panels'] as $panelID => $panel) |
||
202 | { |
||
203 | $panelMap [$i ++] = $panelID; |
||
204 | } |
||
205 | // replace any old values with new panel labels from the request |
||
206 | foreach ($_REQUEST as $key => $value) |
||
207 | { |
||
208 | $components = explode('-', $key); |
||
209 | if ($components [0] == 'panel') |
||
210 | { |
||
211 | $panelMap [$components ['1']] = $value; |
||
212 | } |
||
213 | } |
||
214 | |||
215 | $olddefs = $this->_viewdefs ['panels']; |
||
216 | $origFieldDefs = $this->_getOrigFieldViewDefs(); |
||
217 | // $GLOBALS['log']->debug('origFieldDefs'); |
||
218 | // $GLOBALS['log']->debug($origFieldDefs); |
||
219 | $this->_viewdefs ['panels'] = null; // because the new field properties should replace the old fields, not be merged |
||
220 | |||
221 | if ($this->maxColumns < 1) |
||
222 | { |
||
223 | $this->_fatalError("EditDetailViewParser:invalid maxColumns=" . $this->maxColumns); |
||
224 | } |
||
225 | |||
226 | foreach ($_REQUEST as $slot => $value) |
||
227 | { |
||
228 | $slotComponents = explode('-', $slot); // [0] = 'slot', [1] = panel #, [2] = slot #, [3] = property name |
||
229 | if ($slotComponents [0] == 'slot') |
||
230 | { |
||
231 | $slotNumber = $slotComponents ['2']; |
||
232 | $panelID = $panelMap [$slotComponents ['1']]; |
||
233 | $rowID = floor($slotNumber / $this->maxColumns); |
||
234 | $colID = $slotNumber - ($rowID * $this->maxColumns); |
||
235 | //If the original editview defined this field, copy that over. |
||
236 | if ($slotComponents ['3'] == 'name' && isset($origFieldDefs [$value]) && is_array($origFieldDefs [$value])) |
||
237 | { |
||
238 | $this->_viewdefs ['panels'] [$panelID] [$rowID] [$colID] = $origFieldDefs [$value]; |
||
239 | } |
||
240 | else |
||
241 | { |
||
242 | $property = $slotComponents ['3']; |
||
243 | if ($value == '(filler)') |
||
244 | { |
||
245 | $this->_viewdefs ['panels'] [$panelID] [$rowID] [$colID] = NULL; |
||
246 | } else |
||
247 | { |
||
248 | $this->_viewdefs ['panels'] [$panelID] [$rowID] [$colID] [$property] = $value; |
||
249 | } |
||
250 | } |
||
251 | } |
||
252 | } |
||
253 | |||
254 | // Now handle the (empty) fields - first non-(empty) field goes in at column 0; all other (empty)'s removed |
||
255 | // Do this AFTER reading in all the $_REQUEST parameters as can't guarantee the order of those, and we need to operate on complete rows |
||
256 | foreach ($this->_viewdefs ['panels'] as $panelID => $panel) |
||
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
257 | { |
||
258 | // remove all (empty)s |
||
259 | foreach ($panel as $rowID => $row) |
||
260 | { |
||
261 | $startOfRow = true; |
||
262 | $offset = 0; |
||
263 | foreach ($row as $colID => $col) |
||
264 | { |
||
265 | if ($col ['name'] == '(empty)') |
||
266 | { |
||
267 | // if a leading (empty) then remove (by noting that remaining fields need to be shuffled along) |
||
268 | if ($startOfRow) |
||
269 | { |
||
270 | $offset ++; |
||
271 | } |
||
272 | unset($row [$colID]); |
||
273 | } else |
||
274 | { |
||
275 | $startOfRow = false; |
||
276 | } |
||
277 | } |
||
278 | // reindex to remove leading (empty)s |
||
279 | $newRow = array(); |
||
280 | foreach ($row as $colID => $col) |
||
281 | { |
||
282 | $newRow [$colID - $offset] = $col; |
||
283 | } |
||
284 | $this->_viewdefs ['panels'] [$panelID] [$rowID] = $newRow; |
||
285 | } |
||
286 | } |
||
287 | // _pp($this->_viewdefs); |
||
288 | } |
||
289 | |||
290 | function _padFields () |
||
291 | { |
||
292 | if (! empty($this->_viewdefs)) |
||
293 | { |
||
294 | foreach ($this->_viewdefs ['panels'] as $panelID => $panel) |
||
295 | { |
||
296 | $column = 0; |
||
297 | foreach ($panel as $rowID => $row) |
||
298 | { |
||
299 | // pad between fields on a row |
||
300 | foreach ($row as $colID => $col) |
||
301 | { |
||
302 | for ($i = $column + 1 ; $i < $colID ; $i ++ ) |
||
303 | { |
||
304 | $row [$i] = array('name' => '(empty)', 'label' => '(empty)'); |
||
305 | } |
||
306 | $column = $colID; |
||
307 | } |
||
308 | // now pad out to the end of the row |
||
309 | if (($column + 1) < $this->maxColumns) |
||
310 | { // last column is maxColumns-1 |
||
311 | for ($i = $column + 1 ; $i < $this->maxColumns ; $i ++ ) |
||
312 | { |
||
313 | $row [$i] = array('name' => '(empty)', 'label' => '(empty)'); |
||
314 | } |
||
315 | } |
||
316 | ksort($row); |
||
317 | $this->_viewdefs ['panels'] [$panelID] [$rowID] = $row; |
||
318 | } |
||
319 | } |
||
320 | } |
||
321 | } |
||
322 | |||
323 | |||
324 | // add a new field to the end of a panel |
||
325 | // don't write out (caller should call handleSave() when ready) |
||
326 | function _addField ($properties, $panelID = FALSE) |
||
327 | { |
||
328 | |||
329 | // if a panelID was not passed, use the first available panel in the list |
||
330 | if (!$panelID) { |
||
331 | $panels = array_keys($this->_viewdefs['panels']); |
||
332 | $panelID = $panels[0]; |
||
333 | } |
||
334 | |||
335 | if (isset($this->_viewdefs ['panels'] [$panelID])) |
||
336 | { |
||
337 | |||
338 | // need to clean up the viewdefs before writing them -- Smarty will fail if any fillers/empties are present |
||
339 | foreach ($this->_viewdefs['panels'] as $loop_panelID => $panel_contents) { |
||
340 | foreach ($panel_contents as $row_id => $row) { |
||
341 | foreach ($row as $col_id => $col) { |
||
342 | if ($col['name'] == '(filler)') { |
||
343 | $this->_viewdefs['panels'][$loop_panelID][$row_id][$col_id] = NULL; |
||
344 | } |
||
345 | elseif ($col['name'] == '(empty)') { |
||
346 | unset($this->_viewdefs['panels'][$loop_panelID][$row_id][$col_id]); |
||
347 | } |
||
348 | } |
||
349 | } |
||
350 | } |
||
351 | |||
352 | $panel = $this->_viewdefs ['panels'] [$panelID]; |
||
353 | $lastrow = count($panel) - 1; // index starts at 0 |
||
354 | $lastcol = count($panel [$lastrow]); |
||
355 | |||
356 | // if we're on the last column of the last row, start a new row |
||
357 | // print "lastrow=$lastrow lastcol=$lastcol"; |
||
358 | if ($lastcol >= $this->maxColumns) |
||
359 | { |
||
360 | $lastrow ++; |
||
361 | $this->_viewdefs ['panels'] [$panelID] [$lastrow] = array(); |
||
362 | $lastcol = 0; |
||
363 | } |
||
364 | |||
365 | $this->_viewdefs ['panels'] [$panelID] [$lastrow] [$lastcol] = $properties; |
||
366 | } |
||
367 | } |
||
368 | |||
369 | /* getModelFields returns an array of all fields stored in the database for this module plus those fields in the original layout definition (so we get fields such as Team ID)*/ |
||
370 | function _getModelFields () |
||
371 | { |
||
372 | $modelFields = array(); |
||
373 | $origViewDefs = $this->_getOrigFieldViewDefs(); |
||
374 | // $GLOBALS['log']->debug("Original viewdefs = ".print_r($origViewDefs,true)); |
||
375 | foreach ($origViewDefs as $field => $def) |
||
376 | { |
||
377 | if (!empty($field)) |
||
378 | { |
||
379 | if (! is_array($def)) { |
||
380 | $def = array('name' => $field); |
||
381 | } |
||
382 | // get this field's label - if it has not been explicitly provided, see if the fieldDefs has a label for this field, and if not fallback to the field name |
||
383 | if (! isset($def ['label'])) |
||
384 | { |
||
385 | if (! empty($this->_fieldDefs [$field] ['vname'])) |
||
386 | { |
||
387 | $def ['label'] = $this->_fieldDefs [$field] ['vname']; |
||
388 | } else |
||
389 | { |
||
390 | $def ['label'] = $field; |
||
391 | } |
||
392 | } |
||
393 | $modelFields[$field] = array('name' => $field, 'label' => $def ['label']); |
||
394 | } |
||
395 | } |
||
396 | $GLOBALS['log']->debug(print_r($modelFields,true)); |
||
397 | foreach ($this->_fieldDefs as $field => $def) |
||
398 | { |
||
399 | if ((!empty($def['studio']) && $def['studio'] == 'visible') |
||
400 | || (empty($def['studio']) && (empty($def ['source']) || $def ['source'] == 'db' || $def ['source'] == 'custom_fields') && $def ['type'] != 'id' && strcmp($field, 'deleted') != 0 && (empty($def ['dbType']) || $def ['dbType'] != 'id') && (empty($def ['dbtype']) || $def ['dbtype'] != 'id'))) |
||
401 | { |
||
402 | $label = isset($def['vname']) ? $def['vname'] : $def['name']; |
||
403 | $modelFields [$field] = array('name' => $field, 'label' => $label); |
||
404 | } |
||
405 | else |
||
406 | { |
||
407 | $GLOBALS['log']->debug( get_class($this)."->_getModelFields(): skipping $field from modelFields as it fails the test for inclusion"); |
||
408 | } |
||
409 | } |
||
410 | $GLOBALS['log']->debug( get_class($this)."->_getModelFields(): remaining entries in modelFields are: ".implode(",",array_keys($modelFields))); |
||
411 | return $modelFields; |
||
412 | } |
||
413 | |||
414 | function _parseData ($panels) |
||
415 | { |
||
416 | $fields = array(); |
||
417 | if (empty($panels)) |
||
418 | return; |
||
419 | |||
420 | // Fix for a flexibility in the format of the panel sections - if only one panel, then we don't have a panel level defined, it goes straight into rows |
||
421 | // See EditView2 for similar treatment |
||
422 | if (! empty($panels) && count($panels) > 0) |
||
423 | { |
||
424 | $keys = array_keys($panels); |
||
425 | if (is_numeric($keys [0])) |
||
426 | { |
||
427 | $defaultPanel = $panels; |
||
428 | unset($panels); //blow away current value |
||
429 | $panels [''] = $defaultPanel; |
||
430 | } |
||
431 | } |
||
432 | |||
433 | foreach ($panels as $panelID => $panel) |
||
434 | { |
||
435 | foreach ($panel as $rowID => $row) |
||
436 | { |
||
437 | foreach ($row as $colID => $col) |
||
438 | { |
||
439 | $properties = array(); |
||
440 | |||
441 | if (! empty($col)) |
||
442 | { |
||
443 | if (is_string($col)) |
||
444 | { |
||
445 | $properties ['name'] = $col; |
||
446 | } else if (! empty($col ['name'])) |
||
447 | { |
||
448 | $properties = $col; |
||
449 | } |
||
450 | } else |
||
451 | { |
||
452 | $properties ['name'] = translate('LBL_FILLER'); |
||
453 | } |
||
454 | |||
455 | if (! empty($properties ['name'])) |
||
456 | { |
||
457 | |||
458 | // get this field's label - if it has not been explicity provided, see if the fieldDefs has a label for this field, and if not fallback to the field name |
||
459 | if (! isset($properties ['label'])) |
||
460 | { |
||
461 | if (! empty($this->_fieldDefs [$properties ['name']] ['vname'])) |
||
462 | { |
||
463 | $properties ['label'] = $this->_fieldDefs [$properties ['name']] ['vname']; |
||
464 | } else |
||
465 | { |
||
466 | $properties ['label'] = $properties ['name']; |
||
467 | } |
||
468 | } |
||
469 | |||
470 | $displayData[strtoupper($panelID)] [$rowID] [$colID] = $properties; |
||
471 | |||
472 | } |
||
473 | } |
||
474 | } |
||
475 | } |
||
476 | return $displayData; |
||
477 | } |
||
478 | |||
479 | function _getOrigFieldViewDefs () |
||
480 | { |
||
481 | $origFieldDefs = array(); |
||
482 | $GLOBALS['log']->debug("Original File = ".$this->_originalFile); |
||
483 | if (file_exists($this->_originalFile)) |
||
484 | { |
||
485 | include ($this->_originalFile); |
||
486 | $origdefs = $viewdefs [$this->_module] [$this->_sourceView] ['panels']; |
||
487 | // $GLOBALS['log']->debug($origdefs); |
||
488 | // Fix for a flexibility in the format of the panel sections - if only one panel, then we don't have a panel level defined, it goes straight into rows |
||
489 | // See EditView2 for similar treatment |
||
490 | if (! empty($origdefs) && count($origdefs) > 0) |
||
491 | { |
||
492 | $keys = array_keys($origdefs); |
||
493 | if (is_numeric($keys [0])) |
||
494 | { |
||
495 | $defaultPanel = $origdefs; |
||
496 | unset($origdefs); //blow away current value |
||
497 | $origdefs [''] = $defaultPanel; |
||
498 | } |
||
499 | } |
||
500 | foreach ($origdefs as $pname => $paneldef) |
||
501 | { |
||
502 | foreach ($paneldef as $row) |
||
503 | { |
||
504 | foreach ($row as $fieldDef) |
||
505 | { |
||
506 | if (is_array($fieldDef)) |
||
507 | { |
||
508 | $fieldName = $fieldDef ['name']; |
||
509 | } |
||
510 | else |
||
511 | { |
||
512 | $fieldName = $fieldDef; |
||
513 | } |
||
514 | $origFieldDefs [$fieldName] = $fieldDef; |
||
515 | } |
||
516 | } |
||
517 | } |
||
518 | } |
||
519 | |||
520 | return $origFieldDefs; |
||
521 | } |
||
522 | |||
523 | } |
||
524 | ?> |