1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once 'Services/Form/classes/class.ilIdentifiedMultiValuesInputGUI.php';
5require_once 'Services/UIComponent/Glyph/classes/class.ilGlyphGUI.php';
6
7/**
8 * @author        Björn Heyser <bheyser@databay.de>
9 * @version        $Id$
10 *
11 * @package        Modules/Test(QuestionPool)
12 */
13abstract class ilMultipleImagesInputGUI extends ilIdentifiedMultiValuesInputGUI
14{
15    const RENDERING_TEMPLATE = 'tpl.prop_multi_image_inp.html';
16
17    const ITERATOR_SUBFIELD_NAME = 'iteratorfield';
18    const STORED_IMAGE_SUBFIELD_NAME = 'storedimage';
19    const IMAGE_UPLOAD_SUBFIELD_NAME = 'imageupload';
20
21    const FILE_DATA_INDEX_DODGING_FILE = 'dodging_file';
22    /**
23     * @var bool
24     */
25    protected $editElementOccuranceEnabled = false;
26
27    /**
28     * @var bool
29     */
30    protected $editElementOrderEnabled = false;
31
32    /**
33     * @var array
34     */
35    protected $suffixes = array();
36
37    protected $imageRemovalCommand = 'removeImage';
38
39    protected $imageUploadCommand = 'uploadImage';
40
41    /**
42     * Constructor
43     *
44     * @param	string	$a_title	Title
45     * @param	string	$a_postvar	Post Variable
46     */
47    public function __construct($a_title = "", $a_postvar = "")
48    {
49        global $DIC;
50
51        $this->lng = $DIC->language();
52        parent::__construct($a_title, $a_postvar);
53
54        $this->setSuffixes(array("jpg", "jpeg", "png", "gif"));
55        $this->setSize('25');
56        $this->validationRegexp = "";
57
58        require_once 'Services/Form/classes/class.ilMultipleImagesAdditionalIndexLevelRemover.php';
59        $manipulator = new ilMultipleImagesAdditionalIndexLevelRemover();
60        $manipulator->setPostVar($this->getPostVar());
61        $this->addFormValuesManipulator($manipulator);
62
63        require_once 'Services/Form/classes/class.ilMultipleImagesFileSubmissionDataCompletion.php';
64        $manipulator = new ilMultipleImagesFileSubmissionDataCompletion();
65        $manipulator->setPostVar($this->getPostVar());
66        $this->addFormValuesManipulator($manipulator);
67
68        require_once 'Services/Form/classes/class.ilIdentifiedMultiFilesJsPositionIndexRemover.php';
69        $manipulator = new ilIdentifiedMultiFilesJsPositionIndexRemover();
70        $manipulator->setPostVar($this->getPostVar());
71        $this->addFormValuesManipulator($manipulator);
72
73        require_once 'Services/Form/classes/class.ilMultiFilesSubmitRecursiveSlashesStripper.php';
74        $manipulator = new ilMultiFilesSubmitRecursiveSlashesStripper();
75        $manipulator->setPostVar($this->getPostVar());
76        $this->addFormValuesManipulator($manipulator);
77    }
78
79    /**
80     * Set Accepted Suffixes.
81     *
82     * @param	array	$a_suffixes	Accepted Suffixes
83     */
84    public function setSuffixes($a_suffixes)
85    {
86        $this->suffixes = $a_suffixes;
87    }
88
89    /**
90     * Get Accepted Suffixes.
91     *
92     * @return	array	Accepted Suffixes
93     */
94    public function getSuffixes()
95    {
96        return $this->suffixes;
97    }
98
99    /**
100     * @return string
101     */
102    public function getImageRemovalCommand()
103    {
104        return $this->imageRemovalCommand;
105    }
106
107    /**
108     * @param string $imageRemovalCommand
109     */
110    public function setImageRemovalCommand($imageRemovalCommand)
111    {
112        $this->imageRemovalCommand = $imageRemovalCommand;
113    }
114
115    /**
116     * @return string
117     */
118    public function getImageUploadCommand()
119    {
120        return $this->imageUploadCommand;
121    }
122
123    /**
124     * @param string $imageUploadCommand
125     */
126    public function setImageUploadCommand($imageUploadCommand)
127    {
128        $this->imageUploadCommand = $imageUploadCommand;
129    }
130
131    /**
132     * @return	boolean $editElementOccuranceEnabled
133     */
134    public function isEditElementOccuranceEnabled()
135    {
136        return $this->editElementOccuranceEnabled;
137    }
138
139    /**
140     * @param	boolean	$editElementOccuranceEnabled
141     */
142    public function setEditElementOccuranceEnabled($editElementOccuranceEnabled)
143    {
144        $this->editElementOccuranceEnabled = $editElementOccuranceEnabled;
145    }
146
147    /**
148     * @return boolean
149     */
150    public function isEditElementOrderEnabled()
151    {
152        return $this->editElementOrderEnabled;
153    }
154
155    /**
156     * @param boolean $editElementOrderEnabled
157     */
158    public function setEditElementOrderEnabled($editElementOrderEnabled)
159    {
160        $this->editElementOrderEnabled = $editElementOrderEnabled;
161    }
162
163    /**
164     * @param mixed $value
165     * @return bool
166     */
167    abstract protected function isValidFilenameInput($filenameInput);
168
169    /**
170     * Check input, strip slashes etc. set alert, if input is not ok.
171     *
172     * @return	boolean	$validationSuccess
173     */
174    public function onCheckInput()
175    {
176        $lng = $GLOBALS['DIC'] ? $GLOBALS['DIC']['lng'] : $GLOBALS['lng'];
177        $F = $_FILES[$this->getPostVar()];
178        if ($F && isset($_REQUEST[$this->getPostVar()][self::FILE_DATA_INDEX_DODGING_FILE])) {
179            $F = array_merge(array(self::FILE_DATA_INDEX_DODGING_FILE => $_REQUEST[$this->getPostVar()][self::FILE_DATA_INDEX_DODGING_FILE]), $F);
180        }
181
182        if ($this->getRequired() && !is_array($F['error'])) {
183            $this->setAlert($lng->txt("form_msg_file_no_upload"));
184            return false;
185        } else {
186            foreach ($F['error'] as $index => $error) {
187                // error handling
188                if ($error > 0) {
189                    switch ($error) {
190                    case UPLOAD_ERR_INI_SIZE:
191                        $this->setAlert($lng->txt("form_msg_file_size_exceeds"));
192                        return false;
193                        break;
194
195                    case UPLOAD_ERR_FORM_SIZE:
196                        $this->setAlert($lng->txt("form_msg_file_size_exceeds"));
197                        return false;
198                        break;
199
200                    case UPLOAD_ERR_PARTIAL:
201                        $this->setAlert($lng->txt("form_msg_file_partially_uploaded"));
202                        return false;
203                        break;
204
205                    case UPLOAD_ERR_NO_FILE:
206                        if (!$this->getRequired()) {
207                            break;
208                        } elseif (strlen($F[self::FILE_DATA_INDEX_DODGING_FILE][$index])) {
209                            break;
210                        }
211                        $this->setAlert($lng->txt("form_msg_file_no_upload"));
212                        return false;
213                        break;
214
215                    case UPLOAD_ERR_NO_TMP_DIR:
216                        $this->setAlert($lng->txt("form_msg_file_missing_tmp_dir"));
217                        return false;
218                        break;
219
220                    case UPLOAD_ERR_CANT_WRITE:
221                        $this->setAlert($lng->txt("form_msg_file_cannot_write_to_disk"));
222                        return false;
223                        break;
224
225                    case UPLOAD_ERR_EXTENSION:
226                        $this->setAlert($lng->txt("form_msg_file_upload_stopped_ext"));
227                        return false;
228                        break;
229                }
230                }
231            }
232        }
233
234        if (is_array($F['tmp_name'])) {
235            foreach ($F['tmp_name'] as $index => $tmpname) {
236                $filename = $F['name'][$index];
237                $filename_arr = pathinfo($filename);
238                $suffix = $filename_arr["extension"];
239                $mimetype = $F['type'][$index];
240                $size_bytes = $F['size'][$index];
241                // check suffixes
242                if (strlen($tmpname) && is_array($this->getSuffixes())) {
243                    if (!in_array(strtolower($suffix), $this->getSuffixes())) {
244                        $this->setAlert($lng->txt("form_msg_file_wrong_file_type"));
245                        return false;
246                    }
247                }
248            }
249        }
250
251        foreach ($F['tmp_name'] as $index => $tmpname) {
252            $filename = $F['name'][$index];
253            $filename_arr = pathinfo($filename);
254            $suffix = $filename_arr["extension"];
255            $mimetype = $F['type'][$index];
256            $size_bytes = $F['size'][$index];
257            // virus handling
258            if (strlen($tmpname)) {
259                $vir = ilUtil::virusHandling($tmpname, $filename);
260                if ($vir[0] == false) {
261                    $this->setAlert($lng->txt("form_msg_file_virus_found") . "<br />" . $vir[1]);
262                    return false;
263                }
264            }
265        }
266
267        return $this->checkSubItemsInput();
268    }
269
270    /**
271     * @param string $mode
272     * @return string
273     */
274    public function render($a_mode = "")
275    {
276        $lng = $this->lng;
277
278        $tpl = $this->getTemplate();
279        $i = 0;
280        foreach ($this->getIdentifiedMultiValues() as $identifier => $value) {
281            if ($this->valueHasContentImageSource($value)) {
282                $tpl->setCurrentBlock('image');
283
284                $tpl->setVariable('STORED_IMAGE_SRC', $this->fetchContentImageSourceFromValue($value));
285                $tpl->setVariable('STORED_IMAGE_ALT', ilUtil::prepareFormOutput($this->fetchContentImageTitleFromValue($value)));
286                $tpl->setVariable('STORED_IMAGE_FILENAME', $this->fetchContentImageTitleFromValue($value));
287                $tpl->setVariable("STORED_IMAGE_POST_VAR", $this->getMultiValuePostVarSubFieldPosIndexed($identifier, self::STORED_IMAGE_SUBFIELD_NAME, $i));
288
289                $tpl->setVariable("TXT_DELETE_EXISTING", $lng->txt("delete_existing_file"));
290                $tpl->setVariable("IMAGE_CMD_REMOVE", $this->buildMultiValueSubmitVar($identifier, $i, $this->getImageRemovalCommand()));
291
292                $tpl->parseCurrentBlock();
293            }
294
295            $tpl->setCurrentBlock('addimage');
296
297            $tpl->setVariable("IMAGE_BROWSE", $lng->txt('select_file'));
298            $tpl->setVariable("IMAGE_ID", $this->getMultiValuePosIndexedSubFieldId($identifier, self::IMAGE_UPLOAD_SUBFIELD_NAME, $i));
299            $tpl->setVariable("TXT_IMAGE_SUBMIT", $lng->txt("upload"));
300            $tpl->setVariable("IMAGE_CMD_UPLOAD", $this->buildMultiValueSubmitVar($identifier, $i, $this->getImageUploadCommand()));
301            $tpl->setVariable("UPLOAD_IMAGE_POST_VAR", $this->getMultiValuePostVarSubFieldPosIndexed($identifier, self::IMAGE_UPLOAD_SUBFIELD_NAME, $i));
302            $tpl->setVariable("COUNT_POST_VAR", $this->getMultiValuePostVarSubFieldPosIndexed($identifier, self::ITERATOR_SUBFIELD_NAME, $i));
303
304            $tpl->parseCurrentBlock();
305
306            if ($this->isEditElementOrderEnabled()) {
307                $tpl->setCurrentBlock("move");
308                $tpl->setVariable("ID_UP", $this->getMultiValuePosIndexedSubFieldId($identifier, 'up', $i));
309                $tpl->setVariable("ID_DOWN", $this->getMultiValuePosIndexedSubFieldId($identifier, 'down', $i));
310                $tpl->setVariable("CMD_UP", $this->buildMultiValueSubmitVar($identifier, $i, 'up'));
311                $tpl->setVariable("CMD_DOWN", $this->buildMultiValueSubmitVar($identifier, $i, 'down'));
312                $tpl->setVariable("UP_BUTTON", ilGlyphGUI::get(ilGlyphGUI::UP));
313                $tpl->setVariable("DOWN_BUTTON", ilGlyphGUI::get(ilGlyphGUI::DOWN));
314                $tpl->parseCurrentBlock();
315            }
316
317            if ($this->isEditElementOccuranceEnabled()) {
318                $tpl->setCurrentBlock("row");
319                $tpl->setVariable("ID_ADD", $this->getMultiValuePosIndexedSubFieldId($identifier, 'add', $i));
320                $tpl->setVariable("ID_REMOVE", $this->getMultiValuePosIndexedSubFieldId($identifier, 'remove', $i));
321                $tpl->setVariable("CMD_ADD", $this->buildMultiValueSubmitVar($identifier, $i, 'add'));
322                $tpl->setVariable("CMD_REMOVE", $this->buildMultiValueSubmitVar($identifier, $i, 'remove'));
323                $tpl->setVariable("ADD_BUTTON", ilGlyphGUI::get(ilGlyphGUI::ADD));
324                $tpl->setVariable("REMOVE_BUTTON", ilGlyphGUI::get(ilGlyphGUI::REMOVE));
325                $tpl->parseCurrentBlock();
326            }
327
328            $i++;
329        }
330
331        if (is_array($this->getSuffixes())) {
332            $suff_str = $delim = "";
333            foreach ($this->getSuffixes() as $suffix) {
334                $suff_str .= $delim . "." . $suffix;
335                $delim = ", ";
336            }
337            $tpl->setCurrentBlock('allowed_image_suffixes');
338            $tpl->setVariable("TXT_ALLOWED_SUFFIXES", $lng->txt("file_allowed_suffixes") . " " . $suff_str);
339            $tpl->parseCurrentBlock();
340        }
341        /*
342        $tpl->setCurrentBlock("image_heading");
343        $tpl->setVariable("ANSWER_IMAGE", $lng->txt('answer_image'));
344        $tpl->parseCurrentBlock();
345        */
346
347        $tpl->setVariable("TXT_MAX_SIZE", ilUtil::getFileSizeInfo());
348        $tpl->setVariable("ELEMENT_ID", $this->getPostVar());
349        $tpl->setVariable("TEXT_YES", $lng->txt('yes'));
350        $tpl->setVariable("TEXT_NO", $lng->txt('no'));
351        $tpl->setVariable("DELETE_IMAGE_HEADER", $lng->txt('delete_image_header'));
352        $tpl->setVariable("DELETE_IMAGE_QUESTION", $lng->txt('delete_image_question'));
353        $tpl->setVariable("ANSWER_TEXT", $lng->txt('answer_text'));
354        $tpl->setVariable("COMMANDS_TEXT", $lng->txt('actions'));
355
356        if (!$this->getDisabled()) {
357            $tpl->setCurrentBlock('js_engine_initialisation');
358            $tpl->setVariable('UPLOAD_CMD', $this->getImageUploadCommand());
359            $tpl->setVariable('REMOVE_CMD', $this->getImageRemovalCommand());
360            $tpl->setVariable('ITERATOR', self::ITERATOR_SUBFIELD_NAME);
361            $tpl->setVariable('STORED_IMAGE_POSTVAR', self::STORED_IMAGE_SUBFIELD_NAME);
362            $tpl->setVariable('UPLOAD_IMAGE_POSTVAR', self::IMAGE_UPLOAD_SUBFIELD_NAME);
363            $tpl->parseCurrentBlock();
364
365            $globalTpl = $GLOBALS['DIC'] ? $GLOBALS['DIC']['tpl'] : $GLOBALS['tpl'];
366            $globalTpl->addJavascript("./Services/Form/js/ServiceFormWizardInput.js");
367            $globalTpl->addJavascript("./Services/Form/js/ServiceFormIdentifiedWizardInputExtend.js");
368            //$globalTpl->addJavascript("./Services/Form/js/ServiceFormIdentifiedImageWizardInputConcrete.js");
369        }
370
371        return $tpl->get();
372    }
373
374    /**
375     * @param $value
376     * @return bool
377     */
378    protected function valueHasContentImageSource($value)
379    {
380        return isset($value['src']) && strlen($value['src']);
381    }
382
383    /**
384     * @param $value
385     * @return string
386     */
387    protected function fetchContentImageSourceFromValue($value)
388    {
389        if ($this->valueHasContentImageSource($value)) {
390            return $value['src'];
391        }
392
393        return null;
394    }
395
396    /**
397     * @param $value
398     * @return bool
399     */
400    protected function valueHasContentImageTitle($value)
401    {
402        return isset($value['title']) && strlen($value['title']);
403    }
404
405    /**
406     * @param string $value
407     */
408    protected function fetchContentImageTitleFromValue($value)
409    {
410        if ($this->valueHasContentImageTitle($value)) {
411            return $value['title'];
412        }
413
414        return $this->fetchContentImageSourceFromValue($value);
415    }
416
417    /**
418     * @return ilTemplate
419     */
420    protected function getTemplate()
421    {
422        return new ilTemplate(self::RENDERING_TEMPLATE, true, true, "Services/Form");
423    }
424}
425