1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once("./Services/Form/classes/class.ilFormGUI.php");
5
6// please do not add any more includes here if things are not really
7// highly re-used
8include_once("./Services/Form/classes/class.ilFormPropertyGUI.php");
9include_once("./Services/Form/classes/class.ilSubEnabledFormPropertyGUI.php");
10include_once("./Services/Form/classes/class.ilCheckboxInputGUI.php");
11include_once("./Services/Form/classes/class.ilCustomInputGUI.php");
12include_once("./Services/Form/classes/class.ilDateTimeInputGUI.php");
13include_once("./Services/Form/classes/class.ilFileInputGUI.php");
14include_once("./Services/Form/classes/class.ilImageFileInputGUI.php");
15include_once('./Services/Form/classes/class.ilFlashFileInputGUI.php');
16include_once("./Services/Form/classes/class.ilLocationInputGUI.php");
17include_once("./Services/Form/classes/class.ilRadioGroupInputGUI.php");
18include_once("./Services/Form/classes/class.ilCheckboxGroupInputGUI.php");
19include_once("./Services/Form/classes/class.ilFormSectionHeaderGUI.php");
20include_once("./Services/Form/classes/class.ilSelectInputGUI.php");
21include_once("./Services/Form/classes/class.ilTextAreaInputGUI.php");
22include_once("./Services/Form/classes/class.ilTextInputGUI.php");
23include_once("./Services/Form/classes/class.ilDurationInputGUI.php");
24include_once("./Services/Form/classes/class.ilFeedUrlInputGUI.php");
25include_once("./Services/Form/classes/class.ilNonEditableValueGUI.php");
26include_once("./Services/Form/classes/class.ilRegExpInputGUI.php");
27include_once('./Services/Form/classes/class.ilColorPickerInputGUI.php');
28include_once('./Services/Form/classes/class.ilPasswordInputGUI.php');
29include_once('./Services/Form/classes/class.ilUserLoginInputGUI.php');
30include_once('./Services/Form/classes/class.ilEMailInputGUI.php');
31include_once('./Services/Form/classes/class.ilHiddenInputGUI.php');
32include_once('./Services/Form/classes/class.ilNumberInputGUI.php');
33include_once('./Services/Form/classes/class.ilCSSRectInputGUI.php');
34include_once('./Services/Form/classes/class.ilTextWizardInputGUI.php');
35include_once './Services/Form/classes/class.ilFileWizardInputGUI.php';
36include_once './Services/Form/classes/class.ilFormulaInputGUI.php';
37include_once './Services/Form/classes/class.ilBirthdayInputGUI.php';
38
39/**
40* This class represents a property form user interface
41*
42* @author Alex Killing <alex.killing@gmx.de>
43* @version $Id$
44* @ilCtrl_Calls ilPropertyFormGUI: ilFormPropertyDispatchGUI
45* @ingroup	ServicesForm
46*/
47class ilPropertyFormGUI extends ilFormGUI
48{
49    /**
50     * @var ilLanguage
51     */
52    protected $lng;
53
54    /**
55     * @var ilCtrl
56     */
57    protected $ctrl;
58
59    /**
60     * @var ilTemplate
61     */
62    protected $tpl;
63
64    /**
65     * @var ilObjUser
66     */
67    protected $user;
68
69    /**
70     * @var ilSetting
71     */
72    protected $settings;
73
74    private $buttons = array();
75    private $items = array();
76    protected $mode = "std";
77    protected $check_input_called = false;
78    protected $disable_standard_message = false;
79    protected $top_anchor = "il_form_top";
80    protected $titleicon = false;
81    protected $description = "";
82    protected $tbl_width = false;
83    protected $show_top_buttons = true;
84    protected $hide_labels = false;
85
86
87    /**
88    * Constructor
89    *
90    * @param
91    */
92    public function __construct()
93    {
94        global $DIC;
95
96        $this->lng = $DIC->language();
97        $this->ctrl = $DIC->ctrl();
98
99        $this->user = null;
100        if (isset($DIC["ilUser"])) {
101            $this->user = $DIC["ilUser"];
102        }
103
104        $this->settings = null;
105        if (isset($DIC["ilSetting"])) {
106            $this->settings = $DIC["ilSetting"];
107        }
108
109        $lng = $DIC->language();
110
111        $lng->loadLanguageModule("form");
112
113        // avoid double submission
114        $this->setPreventDoubleSubmission(true);
115
116        // do it as early as possible
117        $this->rebuildUploadedFiles();
118    }
119
120    /**
121    * Execute command.
122    */
123    public function executeCommand()
124    {
125        $ilCtrl = $this->ctrl;
126
127        $next_class = $ilCtrl->getNextClass($this);
128        $cmd = $ilCtrl->getCmd();
129
130        switch ($next_class) {
131            case 'ilformpropertydispatchgui':
132                $ilCtrl->saveParameter($this, 'postvar');
133                include_once './Services/Form/classes/class.ilFormPropertyDispatchGUI.php';
134                $form_prop_dispatch = new ilFormPropertyDispatchGUI();
135                $item = $this->getItemByPostVar($_REQUEST["postvar"]);
136                $form_prop_dispatch->setItem($item);
137                return $ilCtrl->forwardCommand($form_prop_dispatch);
138                break;
139
140        }
141        return false;
142    }
143
144    /**
145     * Set table width
146     *
147     * @access public
148     * @param string table width
149     *
150     */
151    final public function setTableWidth($a_width)
152    {
153        $this->tbl_width = $a_width;
154    }
155
156    /**
157     * get table width
158     *
159     * @access public
160     *
161     */
162    final public function getTableWidth()
163    {
164        return $this->tbl_width;
165    }
166
167    /**
168    * Set Mode ('std', 'subform').
169    *
170    * @param	string	$a_mode	Mode ('std', 'subform')
171    */
172    public function setMode($a_mode)
173    {
174        $this->mode = $a_mode;
175    }
176
177    /**
178    * Get Mode ('std', 'subform').
179    *
180    * @return	string	Mode ('std', 'subform')
181    */
182    public function getMode()
183    {
184        return $this->mode;
185    }
186
187    /**
188    * Set Title.
189    *
190    * @param	string	$a_title	Title
191    */
192    public function setTitle($a_title)
193    {
194        $this->title = $a_title;
195    }
196
197    /**
198    * Get Title.
199    *
200    * @return	string	Title
201    */
202    public function getTitle()
203    {
204        return $this->title;
205    }
206
207    /**
208    * Set TitleIcon.
209    *
210    * @param	string	$a_titleicon	TitleIcon
211    */
212    public function setTitleIcon($a_titleicon)
213    {
214        $this->titleicon = $a_titleicon;
215    }
216
217    /**
218    * Get TitleIcon.
219    *
220    * @return	string	TitleIcon
221    */
222    public function getTitleIcon()
223    {
224        return $this->titleicon;
225    }
226
227    /**
228    * Set description
229    *
230    * @param	string	description
231    */
232    public function setDescription($a_val)
233    {
234        $this->description = $a_val;
235    }
236
237    /**
238    * Get description
239    *
240    * @return	string	description
241    */
242    public function getDescription()
243    {
244        return $this->description;
245    }
246
247    /**
248     * Set top anchor
249     *
250     * @param	string	top anchor
251     * @deprecated
252     */
253    public function setTopAnchor($a_val)
254    {
255        $this->top_anchor = $a_val;
256    }
257
258    /**
259    * Get top anchor
260    *
261    * @return	string	top anchor
262    */
263    public function getTopAnchor()
264    {
265        return $this->top_anchor;
266    }
267
268    /**
269     * Get show top buttons
270     */
271    public function setShowTopButtons($a_val)
272    {
273        $this->show_top_buttons = $a_val;
274    }
275
276    /**
277     * Set show top buttons
278     */
279    public function getShowTopButtons()
280    {
281        return $this->show_top_buttons;
282    }
283
284    /**
285    * Add Item (Property, SectionHeader).
286    *
287    * @param	object	$a_property		Item object
288    */
289    public function addItem($a_item)
290    {
291        $a_item->setParentForm($this);
292        return $this->items[] = $a_item;
293    }
294
295    /**
296    * Remove Item.
297    *
298    * @param	string	$a_postvar		Post Var
299    */
300    public function removeItemByPostVar($a_post_var, $a_remove_unused_headers = false)
301    {
302        foreach ($this->items as $key => $item) {
303            if (method_exists($item, "getPostVar") && $item->getPostVar() == $a_post_var) {
304                unset($this->items[$key]);
305            }
306        }
307
308        // remove section headers if they do not contain any items anymore
309        if ($a_remove_unused_headers) {
310            $unset_keys = array();
311            $last_item = null;
312            $last_key = null;
313            foreach ($this->items as $key => $item) {
314                if ($item instanceof ilFormSectionHeaderGUI && $last_item instanceof ilFormSectionHeaderGUI) {
315                    $unset_keys[] = $last_key;
316                }
317                $last_item = $item;
318                $last_key = $key;
319            }
320            if ($last_item instanceof ilFormSectionHeaderGUI) {
321                $unset_keys[] = $last_key;
322            }
323            foreach ($unset_keys as $key) {
324                unset($this->items[$key]);
325            }
326        }
327    }
328
329    /**
330    * Get Item by POST variable.
331    *
332    * @param	string	$a_postvar		Post Var
333    */
334    public function getItemByPostVar($a_post_var)
335    {
336        foreach ($this->items as $key => $item) {
337            if ($item->getType() != "section_header") {
338                //if ($item->getPostVar() == $a_post_var)
339                $ret = $item->getItemByPostVar($a_post_var);
340                if (is_object($ret)) {
341                    return $ret;
342                }
343            }
344        }
345
346        return false;
347    }
348
349    /**
350    * Set Items
351    *
352    * @param	array	$a_items	array of item objects
353    */
354    public function setItems($a_items)
355    {
356        $this->items = $a_items;
357    }
358
359    /**
360    * Get Items
361    *
362    * @return	array	array of item objects
363    */
364    public function getItems()
365    {
366        return $this->items;
367    }
368
369    /**
370     * returns a flat array of all input items including
371     * the possibly existing subitems recursively
372     *
373     * @return array
374     */
375    public function getInputItemsRecursive()
376    {
377        $inputItems = array();
378
379        foreach ($this->items as $item) {
380            if ($item->getType() == 'section_header') {
381                continue;
382            }
383
384            $inputItems[] = $item;
385
386            if ($item instanceof ilSubEnabledFormPropertyGUI) {
387                $inputItems = array_merge($inputItems, $item->getSubInputItemsRecursive());
388            }
389        }
390
391        return $inputItems;
392    }
393
394    /**
395    * Set disable standard message
396    *
397    * @param	boolean		disable standard message
398    */
399    public function setDisableStandardMessage($a_val)
400    {
401        $this->disable_standard_message = $a_val;
402    }
403
404    /**
405    * Get disable standard message
406    *
407    * @return	boolean		disable standard message
408    */
409    public function getDisableStandardMessage()
410    {
411        return $this->disable_standard_message;
412    }
413
414    /**
415    * Get a value indicating whether the labels should be hidden or not.
416    *
417    * @return	boolean		true, to hide the labels; otherwise, false.
418    */
419    public function getHideLabels()
420    {
421        return $this->hide_labels;
422    }
423
424    /**
425    * Set a value indicating whether the labels should be hidden or not.
426    *
427    * @param	boolean	$a_value	Indicates whether the labels should be hidden.
428    */
429    public function setHideLabels($a_value = true)
430    {
431        $this->hide_labels = $a_value;
432    }
433
434    /**
435    * Set form values from an array
436    *
437    * @param	array	$a_values	Value array (key is post variable name, value is value)
438    */
439    public function setValuesByArray($a_values, $a_restrict_to_value_keys = false)
440    {
441        foreach ($this->items as $item) {
442            if (!($a_restrict_to_value_keys) ||
443                in_array($item->getPostVar(), array_keys($a_values))) {
444                $item->setValueByArray($a_values);
445            }
446        }
447    }
448
449    /**
450    * Set form values from POST values
451    *
452    */
453    public function setValuesByPost()
454    {
455        foreach ($this->items as $item) {
456            $item->setValueByArray($_POST);
457        }
458    }
459
460    /**
461    * Check Post Input. This method also strips slashes and html from
462    * input and sets the alert texts for the items, if the input was not ok.
463    *
464    * @return	boolean		ok true/false
465    */
466    public function checkInput()
467    {
468        global $DIC;
469
470        if ($this->check_input_called) {
471            die("Error: ilPropertyFormGUI->checkInput() called twice.");
472        }
473
474        $ok = true;
475        foreach ($this->items as $item) {
476            $item_ok = $item->checkInput();
477            if (!$item_ok) {
478                $ok = false;
479            }
480        }
481
482        // check if POST is missint completely (if post_max_size exceeded)
483        if (count($this->items) > 0 && !is_array($_POST)) {
484            $ok = false;
485        }
486
487        $this->check_input_called = true;
488
489
490
491        // try to keep uploads for another try
492        if (!$ok && $_POST["ilfilehash"] && sizeof($_FILES)) {
493            $hash = $_POST["ilfilehash"];
494
495            foreach ($_FILES as $field => $data) {
496                // only try to keep files that are ok
497                // see 25484: Wrong error handling when uploading icon instead of tile
498                $item = $this->getItemByPostVar($field);
499                if (!$item->checkInput()) {
500                    continue;
501                }
502                // we support up to 2 nesting levels (see test/assesment)
503                if (is_array($data["tmp_name"])) {
504                    foreach ($data["tmp_name"] as $idx => $upload) {
505                        if (is_array($upload)) {
506                            foreach ($upload as $idx2 => $file) {
507                                if ($file && is_uploaded_file($file)) {
508                                    $file_name = $data["name"][$idx][$idx2];
509                                    $file_type = $data["type"][$idx][$idx2];
510                                    $this->keepFileUpload($hash, $field, $file, $file_name, $file_type, $idx, $idx2);
511                                }
512                            }
513                        } elseif ($upload && is_uploaded_file($upload)) {
514                            $file_name = $data["name"][$idx];
515                            $file_type = $data["type"][$idx];
516                            $this->keepFileUpload($hash, $field, $upload, $file_name, $file_type, $idx);
517                        }
518                    }
519                } else {
520                    $this->keepFileUpload($hash, $field, $data["tmp_name"], $data["name"], $data["type"]);
521                }
522            }
523        }
524        $http = $DIC->http();
525        $txt = $DIC->language()->txt("form_input_not_valid");
526        switch ($http->request()->getHeaderLine('Accept')) {
527            // When JS asks for a valid JSON-Response, we send the success and message as JSON
528            case 'application/json':
529                $stream = \ILIAS\Filesystem\Stream\Streams::ofString(json_encode([
530                    'success' => $ok,
531                    'message' => $txt,
532                ]));
533                $http->saveResponse($http->response()->withBody($stream));
534
535                return $ok;
536
537            // Otherwise we send it using ilUtil and it will be rendered in the Template
538            default:
539
540                if (!$ok && !$this->getDisableStandardMessage()) {
541                    ilUtil::sendFailure($txt);
542                }
543
544                return $ok;
545        }
546    }
547
548    /**
549     *
550     * Returns the value of a HTTP-POST variable, identified by the passed id
551     *
552     * @param	string	The key used for value determination
553     * @param	boolean	A flag whether the form input has to be validated before calling this method
554     * @return	string	The value of a HTTP-POST variable, identified by the passed id
555     * @access	public
556     *
557     */
558    public function getInput($a_post_var, $ensureValidation = true)
559    {
560        // this check ensures, that checkInput has been called (incl. stripSlashes())
561        if (!$this->check_input_called && $ensureValidation) {
562            die("Error: ilPropertyFormGUI->getInput() called without calling checkInput() first.");
563        }
564
565        return $_POST[$a_post_var];
566    }
567
568    /**
569    * Add a custom property.
570    *
571    * @param	string		Title
572    * @param	string		HTML.
573    * @param	string		Info text.
574    * @param	string		Alert text.
575    * @param	boolean		Required field. (Default false)
576    */
577    public function addCustomProperty(
578        $a_title,
579        $a_html,
580        $a_info = "",
581        $a_alert = "",
582        $a_required = false
583    ) {
584        $this->properties[] = array("type" => "custom",
585            "title" => $a_title,
586            "html" => $a_html,
587            "info" => $a_info);
588    }
589
590    /**
591    * Add Command button
592    *
593    * @param	string	Command
594    * @param	string	Text
595    */
596    public function addCommandButton($a_cmd, $a_text, $a_id = "")
597    {
598        $this->buttons[] = array("cmd" => $a_cmd, "text" => $a_text, "id" => $a_id);
599    }
600
601
602    /**
603     * Return all Command buttons
604     *
605     * @return array
606     */
607    public function getCommandButtons()
608    {
609        return $this->buttons;
610    }
611
612    /**
613    * Remove all command buttons
614    */
615    public function clearCommandButtons()
616    {
617        $this->buttons = array();
618    }
619
620    /**
621    * Get Content.
622    */
623    public function getContent()
624    {
625        global $DIC;
626        $lng = $this->lng;
627        $tpl = $DIC["tpl"];
628        $ilSetting = $this->settings;
629
630        include_once("./Services/YUI/classes/class.ilYuiUtil.php");
631        ilYuiUtil::initEvent();
632        ilYuiUtil::initDom();
633        ilYuiUtil::initAnimation();
634
635        $tpl->addJavaScript("./Services/JavaScript/js/Basic.js");
636        $tpl->addJavaScript("Services/Form/js/Form.js");
637
638        $this->tpl = new ilTemplate("tpl.property_form.html", true, true, "Services/Form");
639
640        // check if form has not title and first item is a section header
641        // -> use section header for title and remove section header
642        // -> command buttons are presented on top
643        $fi = $this->items[0];
644        if ($this->getMode() == "std" &&
645            $this->getTitle() == "" &&
646            is_object($fi) && $fi->getType() == "section_header"
647            ) {
648            $this->setTitle($fi->getTitle());
649            unset($this->items[0]);
650        }
651
652
653        // title icon
654        if ($this->getTitleIcon() != "" && @is_file($this->getTitleIcon())) {
655            $this->tpl->setCurrentBlock("title_icon");
656            $this->tpl->setVariable("IMG_ICON", $this->getTitleIcon());
657            $this->tpl->parseCurrentBlock();
658        }
659
660        // title
661        if ($this->getTitle() != "") {
662            // commands on top
663            if (count($this->buttons) > 0 && $this->getShowTopButtons() && count($this->items) > 2) {
664                // command buttons
665                foreach ($this->buttons as $button) {
666                    $this->tpl->setCurrentBlock("cmd2");
667                    $this->tpl->setVariable("CMD", $button["cmd"]);
668                    $this->tpl->setVariable("CMD_TXT", $button["text"]);
669                    if ($button["id"] != "") {
670                        $this->tpl->setVariable("CMD2_ID", " id='" . $button["id"] . "_top'");
671                    }
672                    $this->tpl->parseCurrentBlock();
673                }
674                $this->tpl->setCurrentBlock("commands2");
675                $this->tpl->parseCurrentBlock();
676            }
677
678            if (is_object($ilSetting)) {
679                if ($ilSetting->get('char_selector_availability') > 0) {
680                    require_once 'Services/UIComponent/CharSelector/classes/class.ilCharSelectorGUI.php';
681                    if (ilCharSelectorGUI::_isAllowed()) {
682                        $char_selector = ilCharSelectorGUI::_getCurrentGUI();
683                        if ($char_selector->getConfig()->getAvailability() == ilCharSelectorConfig::ENABLED) {
684                            $char_selector->addToPage();
685                            $this->tpl->TouchBlock('char_selector');
686                        }
687                    }
688                }
689            }
690
691            $this->tpl->setCurrentBlock("header");
692            $this->tpl->setVariable("TXT_TITLE", $this->getTitle());
693            //$this->tpl->setVariable("LABEL", $this->getTopAnchor());
694            $this->tpl->setVariable("TXT_DESCRIPTION", $this->getDescription());
695            $this->tpl->parseCurrentBlock();
696        }
697        $this->tpl->touchBlock("item");
698
699        // properties
700        $this->required_text = false;
701        foreach ($this->items as $item) {
702            if ($item->getType() != "hidden") {
703                $this->insertItem($item);
704            }
705        }
706
707        // required
708        if ($this->required_text && $this->getMode() == "std") {
709            $this->tpl->setCurrentBlock("required_text");
710            $this->tpl->setVariable("TXT_REQUIRED", $lng->txt("required_field"));
711            $this->tpl->parseCurrentBlock();
712        }
713
714        // command buttons
715        foreach ($this->buttons as $button) {
716            $this->tpl->setCurrentBlock("cmd");
717            $this->tpl->setVariable("CMD", $button["cmd"]);
718            $this->tpl->setVariable("CMD_TXT", $button["text"]);
719
720            if ($button["id"] != "") {
721                $this->tpl->setVariable("CMD_ID", " id='" . $button["id"] . "'");
722            }
723
724            $this->tpl->parseCurrentBlock();
725        }
726
727        // #18808
728        if ($this->getMode() != "subform") {
729            // try to keep uploads even if checking input fails
730            if ($this->getMultipart()) {
731                $hash = $_POST["ilfilehash"];
732                if (!$hash) {
733                    $hash = md5(uniqid(mt_rand(), true));
734                }
735                $fhash = new ilHiddenInputGUI("ilfilehash");
736                $fhash->setValue($hash);
737                $this->addItem($fhash);
738            }
739        }
740
741        // hidden properties
742        $hidden_fields = false;
743        foreach ($this->items as $item) {
744            if ($item->getType() == "hidden") {
745                $item->insert($this->tpl);
746                $hidden_fields = true;
747            }
748        }
749
750        if ($this->required_text || count($this->buttons) > 0 || $hidden_fields) {
751            $this->tpl->setCurrentBlock("commands");
752            $this->tpl->parseCurrentBlock();
753        }
754
755
756        if ($this->getMode() == "subform") {
757            $this->tpl->touchBlock("sub_table");
758        } else {
759            $this->tpl->touchBlock("std_table");
760            $this->tpl->setVariable('STD_TABLE_WIDTH', $this->getTableWidth());
761        }
762
763        return $this->tpl->get();
764    }
765
766    protected function hideRequired($a_type)
767    {
768        // #15818
769        return in_array($a_type, array("non_editable_value"));
770    }
771
772    public function insertItem($item, $a_sub_item = false)
773    {
774        global $DIC;
775        $tpl = $DIC["tpl"];
776        ;
777        $lng = $this->lng;
778
779
780        $cfg = array();
781
782        //if(method_exists($item, "getMulti") && $item->getMulti())
783        if ($item instanceof ilMultiValuesItem && $item->getMulti()) {
784            $tpl->addJavascript("./Services/Form/js/ServiceFormMulti.js");
785
786            $this->tpl->setCurrentBlock("multi_in");
787            $this->tpl->setVariable("ID", $item->getFieldId());
788            $this->tpl->parseCurrentBlock();
789
790            $this->tpl->touchBlock("multi_out");
791
792
793            // add hidden item to enable preset multi items
794            // not used yet, should replace hidden field stuff
795            $multi_values = $item->getMultiValues();
796            if (is_array($multi_values) && sizeof($multi_values) > 1) {
797                $multi_value = new ilHiddenInputGUI("ilMultiValues~" . $item->getPostVar());
798                $multi_value->setValue(implode("~", $multi_values));
799                $this->addItem($multi_value);
800            }
801            $cfg["multi_values"] = $multi_values;
802        }
803
804        $item->insert($this->tpl);
805
806        if ($item->getType() == "file" || $item->getType() == "image_file") {
807            $this->setMultipart(true);
808        }
809
810        if ($item->getType() != "section_header") {
811            $cfg["id"] = $item->getFieldId();
812
813            // info text
814            if ($item->getInfo() != "") {
815                $this->tpl->setCurrentBlock("description");
816                $this->tpl->setVariable(
817                    "PROPERTY_DESCRIPTION",
818                    $item->getInfo()
819                );
820                $this->tpl->parseCurrentBlock();
821            }
822
823            if ($this->getMode() == "subform") {
824                // required
825                if (!$this->hideRequired($item->getType())) {
826                    if ($item->getRequired()) {
827                        $this->tpl->touchBlock("sub_required");
828                        $this->required_text = true;
829                    }
830                }
831
832                // hidden title (for accessibility, e.g. file upload)
833                if ($item->getHiddenTitle() != "") {
834                    $this->tpl->setCurrentBlock("sub_hid_title");
835                    $this->tpl->setVariable(
836                        "SPHID_TITLE",
837                        $item->getHiddenTitle()
838                    );
839                    $this->tpl->parseCurrentBlock();
840                }
841
842                $this->tpl->setCurrentBlock("sub_prop_start");
843                $this->tpl->setVariable("PROPERTY_TITLE", $item->getTitle());
844                $this->tpl->setVariable("PROPERTY_CLASS", "il_" . $item->getType());
845                if ($item->getType() != "non_editable_value" && $item->getFormLabelFor() != "") {
846                    $this->tpl->setVariable("FOR_ID", ' for="'.$item->getFormLabelFor().'" ');
847                }
848                $this->tpl->setVariable("LAB_ID", $item->getFieldId());
849                $this->tpl->parseCurrentBlock();
850            } else {
851                // required
852                if (!$this->hideRequired($item->getType())) {
853                    if ($item->getRequired()) {
854                        $this->tpl->touchBlock("required");
855                        $this->required_text = true;
856                    }
857                }
858
859                // hidden title (for accessibility, e.g. file upload)
860                if ($item->getHiddenTitle() != "") {
861                    $this->tpl->setCurrentBlock("std_hid_title");
862                    $this->tpl->setVariable(
863                        "PHID_TITLE",
864                        $item->getHiddenTitle()
865                    );
866                    $this->tpl->parseCurrentBlock();
867                }
868
869                $this->tpl->setCurrentBlock("std_prop_start");
870                $this->tpl->setVariable("PROPERTY_TITLE", $item->getTitle());
871                if ($item->getType() != "non_editable_value" && $item->getFormLabelFor() != "") {
872                    $this->tpl->setVariable("FOR_ID", ' for="'.$item->getFormLabelFor().'" ');
873                }
874                $this->tpl->setVariable("LAB_ID", $item->getFieldId());
875                if ($this->getHideLabels()) {
876                    $this->tpl->setVariable("HIDE_LABELS_STYLE", " ilFormOptionHidden");
877                }
878                $this->tpl->parseCurrentBlock();
879            }
880
881            // alert
882            if ($item->getType() != "non_editable_value" && $item->getAlert() != "") {
883                $this->tpl->setCurrentBlock("alert");
884                $this->tpl->setVariable(
885                    "IMG_ALERT",
886                    ilUtil::getImagePath("icon_alert.svg")
887                );
888                $this->tpl->setVariable(
889                    "ALT_ALERT",
890                    $lng->txt("alert")
891                );
892                $this->tpl->setVariable(
893                    "TXT_ALERT",
894                    $item->getAlert()
895                );
896                $this->tpl->parseCurrentBlock();
897            }
898
899            // subitems
900            $sf = null;
901            if ($item->getType() != "non_editable_value" or 1) {
902                $sf = $item->getSubForm();
903                if ($item->hideSubForm() && is_object($sf)) {
904                    $this->tpl->setCurrentBlock("sub_form_hide");
905                    $this->tpl->setVariable("DSFID", $item->getFieldId());
906                    $this->tpl->parseCurrentBlock();
907                }
908            }
909
910
911            $sf_content = "";
912            if (is_object($sf)) {
913                $sf_content = $sf->getContent();
914                if ($sf->getMultipart()) {
915                    $this->setMultipart(true);
916                }
917                $this->tpl->setCurrentBlock("sub_form");
918                $this->tpl->setVariable("PROP_SUB_FORM", $sf_content);
919                $this->tpl->setVariable("SFID", $item->getFieldId());
920                $this->tpl->parseCurrentBlock();
921            }
922
923            $this->tpl->setCurrentBlock("prop");
924            /* not used yet
925            $this->tpl->setVariable("ID", $item->getFieldId());
926            $this->tpl->setVariable("CFG", ilJsonUtil::encode($cfg));*/
927            $this->tpl->parseCurrentBlock();
928        }
929
930
931        $this->tpl->touchBlock("item");
932    }
933
934    public function getHTML()
935    {
936        $html = parent::getHTML();
937
938        // #13531 - get content that has to reside outside of the parent form tag, e.g. panels/layers
939        foreach ($this->items as $item) {
940            // #13536 - ilFormSectionHeaderGUI does NOT extend ilFormPropertyGUI ?!
941            if (method_exists($item, "getContentOutsideFormTag")) {
942                $outside = $item->getContentOutsideFormTag();
943                if ($outside) {
944                    $html .= $outside;
945                }
946            }
947        }
948
949        return $html;
950    }
951
952
953    //
954    // UPLOAD HANDLING
955    //
956
957    /**
958     * Import upload into temp directory
959     *
960     * @param string $a_hash unique form hash
961     * @param string $a_field form field
962     * @param string $a_tmp_name temp file name
963     * @param string $a_name original file name
964     * @param string $a_type file mime type
965     * @param mixed $a_index form field index (if array)
966     * @param mixed $a_sub_index form field subindex (if array)
967     * @return bool
968     */
969    protected function keepFileUpload($a_hash, $a_field, $a_tmp_name, $a_name, $a_type, $a_index = null, $a_sub_index = null)
970    {
971        if (trim($a_tmp_name) == "") {
972            return;
973        }
974
975        $a_name = ilUtil::getAsciiFileName($a_name);
976
977        $tmp_file_name = implode("~~", array(session_id(),
978            $a_hash,
979            $a_field,
980            $a_index,
981            $a_sub_index,
982            str_replace("/", "~~", $a_type),
983            str_replace("~~", "_", $a_name)));
984
985        // make sure temp directory exists
986        $temp_path = ilUtil::getDataDir() . "/temp";
987        if (!is_dir($temp_path)) {
988            ilUtil::createDirectory($temp_path);
989        }
990
991        ilUtil::moveUploadedFile($a_tmp_name, $tmp_file_name, $temp_path . "/" . $tmp_file_name);
992
993        /** @var ilFileInputGUI $file_input */
994        $file_input = $this->getItemByPostVar($a_field);
995        $file_input->setPending($a_name);
996    }
997
998    /**
999     * Get file upload data
1000     *
1001     * @param string $a_field form field
1002     * @param mixed $a_index form field index (if array)
1003     * @param mixed $a_sub_index form field subindex (if array)
1004     * @return array (tmp_name, name, type, error, size, is_upload)
1005     */
1006    public function getFileUpload($a_field, $a_index = null, $a_sub_index = null)
1007    {
1008        $res = array();
1009        if ($a_index) {
1010            if ($_FILES[$a_field]["tmp_name"][$a_index][$a_sub_index]) {
1011                $res = array(
1012                    "tmp_name" => $_FILES[$a_field]["tmp_name"][$a_index][$a_sub_index],
1013                    "name" => $_FILES[$a_field]["name"][$a_index][$a_sub_index],
1014                    "type" => $_FILES[$a_field]["type"][$a_index][$a_sub_index],
1015                    "error" => $_FILES[$a_field]["error"][$a_index][$a_sub_index],
1016                    "size" => $_FILES[$a_field]["size"][$a_index][$a_sub_index],
1017                    "is_upload" => true
1018                );
1019            }
1020        } elseif ($a_sub_index) {
1021            if ($_FILES[$a_field]["tmp_name"][$a_index]) {
1022                $res = array(
1023                    "tmp_name" => $_FILES[$a_field]["tmp_name"][$a_index],
1024                    "name" => $_FILES[$a_field]["name"][$a_index],
1025                    "type" => $_FILES[$a_field]["type"][$a_index],
1026                    "error" => $_FILES[$a_field]["error"][$a_index],
1027                    "size" => $_FILES[$a_field]["size"][$a_index],
1028                    "is_upload" => true
1029                );
1030            }
1031        } else {
1032            if ($_FILES[$a_field]["tmp_name"]) {
1033                $res = array(
1034                    "tmp_name" => $_FILES[$a_field]["tmp_name"],
1035                    "name" => $_FILES[$a_field]["name"],
1036                    "type" => $_FILES[$a_field]["type"],
1037                    "error" => $_FILES[$a_field]["error"],
1038                    "size" => $_FILES[$a_field]["size"],
1039                    "is_upload" => true
1040                );
1041            }
1042        }
1043        return $res;
1044    }
1045
1046    /**
1047     * Was any file uploaded?
1048     *
1049     * @param string $a_field form field
1050     * @param mixed $a_index form field index (if array)
1051     * @param mixed $a_sub_index form field subindex (if array)
1052     * @return bool
1053     */
1054    public function hasFileUpload($a_field, $a_index = null, $a_sub_index = null)
1055    {
1056        $data = $this->getFileUpload($a_field, $a_index, $a_sub_index);
1057        return (bool) $data["tmp_name"];
1058    }
1059
1060    /**
1061     * Move upload to target directory
1062     *
1063     * @param string $a_target_directory target directory (without filename!)
1064     * @param string $a_field form field
1065     * @param string $a_target_name target file name (if different from uploaded file)
1066     * @param mixed $a_index form field index (if array)
1067     * @param mixed $a_sub_index form field subindex (if array)
1068     * @return string target file name incl. path
1069     */
1070    public function moveFileUpload($a_target_directory, $a_field, $a_target_name = null, $a_index = null, $a_sub_index = null)
1071    {
1072        if (!is_dir($a_target_directory)) {
1073            return;
1074        }
1075
1076        $data = $this->getFileUpload($a_field, $a_index, $a_sub_index);
1077        if ($data["tmp_name"] && file_exists($data["tmp_name"])) {
1078            if ($a_target_name) {
1079                $data["name"] = $a_target_name;
1080            }
1081
1082            $target_file = $a_target_directory . "/" . $data["name"];
1083            $target_file = str_replace("//", "/", $target_file);
1084
1085            if ($data["is_upload"]) {
1086                if (!ilUtil::moveUploadedFile($data["tmp_name"], $data["name"], $target_file)) {
1087                    return;
1088                }
1089            } else {
1090                if (!rename($data["tmp_name"], $target_file)) {
1091                    return;
1092                }
1093            }
1094
1095            return $target_file;
1096        }
1097    }
1098
1099    /**
1100     * try to rebuild files
1101     */
1102    protected function rebuildUploadedFiles()
1103    {
1104        if (isset($_POST["ilfilehash"]) && $_POST["ilfilehash"]) {
1105            $temp_path = ilUtil::getDataDir() . "/temp";
1106            if (is_dir($temp_path)) {
1107                $reload = array();
1108
1109                $temp_files = glob($temp_path . "/" . session_id() . "~~" . $_POST["ilfilehash"] . "~~*");
1110                if (is_array($temp_files)) {
1111                    foreach ($temp_files as $full_file) {
1112                        $file = explode("~~", basename($full_file));
1113                        $field = $file[2];
1114                        $idx = $file[3];
1115                        $idx2 = $file[4];
1116                        $type = $file[5] . "/" . $file[6];
1117                        $name = $file[7];
1118
1119                        if ($idx2 != "") {
1120                            if (!$_FILES[$field]["tmp_name"][$idx][$idx2]) {
1121                                $_FILES[$field]["tmp_name"][$idx][$idx2] = $full_file;
1122                                $_FILES[$field]["name"][$idx][$idx2] = $name;
1123                                $_FILES[$field]["type"][$idx][$idx2] = $type;
1124                                $_FILES[$field]["error"][$idx][$idx2] = 0;
1125                                $_FILES[$field]["size"][$idx][$idx2] = filesize($full_file);
1126                            }
1127                        } elseif ($idx != "") {
1128                            if (!$_FILES[$field]["tmp_name"][$idx]) {
1129                                $_FILES[$field]["tmp_name"][$idx] = $full_file;
1130                                $_FILES[$field]["name"][$idx] = $name;
1131                                $_FILES[$field]["type"][$idx] = $type;
1132                                $_FILES[$field]["error"][$idx] = 0;
1133                                $_FILES[$field]["size"][$idx] = filesize($full_file);
1134                            }
1135                        } else {
1136                            if (!$_FILES[$field]["tmp_name"]) {
1137                                $_FILES[$field]["tmp_name"] = $full_file;
1138                                $_FILES[$field]["name"] = $name;
1139                                $_FILES[$field]["type"] = $type;
1140                                $_FILES[$field]["error"] = 0;
1141                                $_FILES[$field]["size"] = filesize($full_file);
1142                            }
1143                        }
1144                    }
1145                }
1146            }
1147        }
1148    }
1149}
1150