1<?php
2/* Copyright (c) 1998-2009 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4include_once 'Services/UIComponent/Toolbar/interfaces/interface.ilToolbarItem.php';
5include_once("./Services/Form/classes/class.ilSubEnabledFormPropertyGUI.php");
6
7/**
8* This class represents a file property in a property form.
9*
10* @author Alex Killing <alex.killing@gmx.de>
11* @version $Id$
12* @ingroup	ServicesForm
13*/
14class ilFileInputGUI extends ilSubEnabledFormPropertyGUI implements ilToolbarItem
15{
16    /**
17     * @var ilLanguage
18     */
19    protected $lng;
20
21    private $filename;
22    private $filename_post;
23    protected $size = 40;
24    protected $pending;
25    protected $allow_deletion;
26
27    protected static $check_wsp_quota;
28
29    /**
30     * @var array
31     */
32    protected $forbidden_suffixes = array();
33
34    /**
35    * Constructor
36    *
37    * @param	string	$a_title	Title
38    * @param	string	$a_postvar	Post Variable
39    */
40    public function __construct($a_title = "", $a_postvar = "")
41    {
42        global $DIC;
43
44        $this->lng = $DIC->language();
45        $lng = $DIC->language();
46
47        parent::__construct($a_title, $a_postvar);
48        $this->setType("file");
49        $this->setHiddenTitle("(" . $lng->txt("form_file_input") . ")");
50    }
51
52    /**
53    * Set value by array
54    *
55    * @param	array	$a_values	value array
56    */
57    public function setValueByArray($a_values)
58    {
59        if (!is_array($a_values[$this->getPostVar()])) {
60            $this->setValue($a_values[$this->getPostVar()]);
61        }
62        $this->setFilename($a_values[$this->getFileNamePostVar()]);
63    }
64
65    /**
66    * Set Value. (used for displaying file title of existing file below input field)
67    *
68    * @param	string	$a_value	Value
69    */
70    public function setValue($a_value)
71    {
72        $this->value = $a_value;
73    }
74
75    /**
76    * Get Value.
77    *
78    * @return	string	Value
79    */
80    public function getValue()
81    {
82        return $this->value;
83    }
84
85    /**
86    * Set Size.
87    *
88    * @param	int	$a_size	Size
89    */
90    public function setSize($a_size)
91    {
92        $this->size = $a_size;
93    }
94
95    /**
96    * Get Size.
97    *
98    * @return	int	Size
99    */
100    public function getSize()
101    {
102        return $this->size;
103    }
104
105    /**
106     * Set filename value (if filename selection is enabled)
107     *
108     * @param string $a_val
109     */
110    public function setFilename($a_val)
111    {
112        $this->filename = $a_val;
113    }
114
115    /**
116    * Get Value.
117    *
118    * @return	string	Value
119    */
120    public function getFilename()
121    {
122        return $this->filename;
123    }
124
125
126
127    /**
128    * Set Accepted Suffixes.
129    *
130    * @param	array	$a_suffixes	Accepted Suffixes
131    */
132    public function setSuffixes($a_suffixes)
133    {
134        $this->suffixes = $a_suffixes;
135    }
136
137    /**
138    * Get Accepted Suffixes.
139    *
140    * @return	array	Accepted Suffixes
141    */
142    public function getSuffixes()
143    {
144        return $this->suffixes;
145    }
146
147    /**
148     * Set forbidden Suffixes.
149     *
150     * @param	array	$a_suffixes	forbidden Suffixes
151     */
152    public function setForbiddenSuffixes($a_suffixes)
153    {
154        $this->forbidden_suffixes = $a_suffixes;
155    }
156
157    /**
158     * Get Accepted Suffixes.
159     *
160     * @return	array	forbidden Suffixes
161     */
162    public function getForbiddenSuffixes()
163    {
164        return $this->forbidden_suffixes;
165    }
166
167    /**
168     * Set pending filename value
169     *
170     * @param string $a_val
171     */
172    public function setPending($a_val)
173    {
174        $this->pending = $a_val;
175    }
176
177    /**
178    * Get pending filename
179    *
180    * @return	string	Value
181    */
182    public function getPending()
183    {
184        return $this->pending;
185    }
186
187    /**
188     * If enabled, users get the possibility to enter a filename for the uploaded file
189     *
190     * @access public
191     * @param string post variable
192     *
193     */
194    public function enableFileNameSelection($a_post_var)
195    {
196        $this->filename_selection = true;
197        $this->filename_post = $a_post_var;
198    }
199
200    /**
201     * Check if filename selection is enabled
202     *
203     * @access public
204     * @return bool enabled/disabled
205     */
206    public function isFileNameSelectionEnabled()
207    {
208        return $this->filename_selection ? true : false;
209    }
210
211    /**
212     * Get file name post var
213     *
214     * @access public
215     * @param string file name post var
216     *
217     */
218    public function getFileNamePostVar()
219    {
220        return $this->filename_post;
221    }
222
223    /**
224     * Set allow deletion
225     *
226     * @param boolean $a_val allow deletion
227     */
228    public function setALlowDeletion($a_val)
229    {
230        $this->allow_deletion = $a_val;
231    }
232
233    /**
234     * Get allow deletion
235     *
236     * @return boolean allow deletion
237     */
238    public function getALlowDeletion()
239    {
240        return $this->allow_deletion;
241    }
242
243    /**
244    * Check input, strip slashes etc. set alert, if input is not ok.
245    *
246    * @return	boolean		Input ok, true/false
247    */
248    public function checkInput()
249    {
250        $lng = $this->lng;
251
252        // #18756
253        if ($this->getDisabled()) {
254            return true;
255        }
256
257        // if no information is received, something went wrong
258        // this is e.g. the case, if the post_max_size has been exceeded
259        if (!is_array($_FILES[$this->getPostVar()])) {
260            $this->setAlert($lng->txt("form_msg_file_size_exceeds"));
261            return false;
262        }
263
264        $_FILES[$this->getPostVar()]["name"] = ilUtil::stripSlashes($_FILES[$this->getPostVar()]["name"]);
265
266        include_once("./Services/Utilities/classes/class.ilStr.php");
267        $_FILES[$this->getPostVar()]["name"] = ilStr::normalizeUtf8String($_FILES[$this->getPostVar()]["name"]);
268
269        // remove trailing '/'
270        $_FILES[$this->getPostVar()]["name"] = rtrim($_FILES[$this->getPostVar()]["name"], '/');
271
272        $filename = $_FILES[$this->getPostVar()]["name"];
273        $filename_arr = pathinfo($_FILES[$this->getPostVar()]["name"]);
274        $suffix = $filename_arr["extension"];
275        $mimetype = $_FILES[$this->getPostVar()]["type"];
276        $size_bytes = $_FILES[$this->getPostVar()]["size"];
277        $temp_name = $_FILES[$this->getPostVar()]["tmp_name"];
278        $error = $_FILES[$this->getPostVar()]["error"];
279        $_POST[$this->getPostVar()] = $_FILES[$this->getPostVar()];
280
281        // error handling
282        if ($error > 0) {
283            switch ($error) {
284                case UPLOAD_ERR_INI_SIZE:
285                    $this->setAlert($lng->txt("form_msg_file_size_exceeds"));
286                    return false;
287                    break;
288
289                case UPLOAD_ERR_FORM_SIZE:
290                    $this->setAlert($lng->txt("form_msg_file_size_exceeds"));
291                    return false;
292                    break;
293
294                case UPLOAD_ERR_PARTIAL:
295                    $this->setAlert($lng->txt("form_msg_file_partially_uploaded"));
296                    return false;
297                    break;
298
299                case UPLOAD_ERR_NO_FILE:
300                    if ($this->getRequired()) {
301                        if (!strlen($this->getValue())) {
302                            $this->setAlert($lng->txt("form_msg_file_no_upload"));
303                            return false;
304                        }
305                    }
306                    break;
307
308                case UPLOAD_ERR_NO_TMP_DIR:
309                    $this->setAlert($lng->txt("form_msg_file_missing_tmp_dir"));
310                    return false;
311                    break;
312
313                case UPLOAD_ERR_CANT_WRITE:
314                    $this->setAlert($lng->txt("form_msg_file_cannot_write_to_disk"));
315                    return false;
316                    break;
317
318                case UPLOAD_ERR_EXTENSION:
319                    $this->setAlert($lng->txt("form_msg_file_upload_stopped_ext"));
320                    return false;
321                    break;
322            }
323        }
324
325        // check suffixes
326        if ($_FILES[$this->getPostVar()]["tmp_name"] != "") {
327            if (is_array($this->forbidden_suffixes) && in_array(strtolower($suffix), $this->forbidden_suffixes)) {
328                $this->setAlert($lng->txt("form_msg_file_type_is_not_allowed") . " (" . $suffix . ")");
329                return false;
330            }
331            if (is_array($this->getSuffixes()) && count($this->getSuffixes()) > 0) {
332                if (!in_array(strtolower($suffix), $this->getSuffixes())) {
333                    $this->setAlert($lng->txt("form_msg_file_wrong_file_type"));
334                    return false;
335                }
336            }
337        }
338
339        // virus handling
340        if ($_FILES[$this->getPostVar()]["tmp_name"] != "") {
341            $vir = ilUtil::virusHandling($temp_name, $filename);
342            if ($vir[0] == false) {
343                $this->setAlert($lng->txt("form_msg_file_virus_found") . "<br />" . $vir[1]);
344                return false;
345            }
346        }
347
348        return true;
349    }
350
351    /**
352    * Render html
353    */
354    public function render($a_mode = "")
355    {
356        $lng = $this->lng;
357
358        $quota_exceeded = $quota_legend = false;
359        if (self::$check_wsp_quota) {
360            include_once "Services/DiskQuota/classes/class.ilDiskQuotaHandler.php";
361            if (!ilDiskQuotaHandler::isUploadPossible()) {
362                $lng->loadLanguageModule("file");
363                $quota_exceeded = $lng->txt("personal_resources_quota_exceeded_warning");
364            } else {
365                $quota_legend = ilDiskQuotaHandler::getStatusLegend();
366            }
367        }
368
369        $f_tpl = new ilTemplate("tpl.prop_file.html", true, true, "Services/Form");
370
371
372        // show filename selection if enabled
373        if ($this->isFileNameSelectionEnabled()) {
374            $f_tpl->setCurrentBlock('filename');
375            $f_tpl->setVariable('POST_FILENAME', $this->getFileNamePostVar());
376            $f_tpl->setVariable('VAL_FILENAME', $this->getFilename());
377            $f_tpl->setVariable('FILENAME_ID', $this->getFieldId());
378            $f_tpl->setVAriable('TXT_FILENAME_HINT', $lng->txt('if_no_title_then_filename'));
379            $f_tpl->parseCurrentBlock();
380        } else {
381            if (trim($this->getValue() != "")) {
382                if (!$this->getDisabled() && $this->getALlowDeletion()) {
383                    $f_tpl->setCurrentBlock("delete_bl");
384                    $f_tpl->setVariable("POST_VAR_D", $this->getPostVar());
385                    $f_tpl->setVariable(
386                        "TXT_DELETE_EXISTING",
387                        $lng->txt("delete_existing_file")
388                    );
389                    $f_tpl->parseCurrentBlock();
390                }
391
392                $f_tpl->setCurrentBlock('prop_file_propval');
393                $f_tpl->setVariable('FILE_VAL', $this->getValue());
394                $f_tpl->parseCurrentBlock();
395            }
396        }
397
398        if ($a_mode != "toolbar") {
399            if (!$quota_exceeded) {
400                $this->outputSuffixes($f_tpl);
401
402                $f_tpl->setCurrentBlock("max_size");
403                $f_tpl->setVariable("TXT_MAX_SIZE", $lng->txt("file_notice") . " " .
404                    $this->getMaxFileSizeString());
405                $f_tpl->parseCurrentBlock();
406
407                if ($quota_legend) {
408                    $f_tpl->setVariable("TXT_MAX_SIZE", $quota_legend);
409                    $f_tpl->parseCurrentBlock();
410                }
411            } else {
412                $f_tpl->setCurrentBlock("max_size");
413                $f_tpl->setVariable("TXT_MAX_SIZE", $quota_exceeded);
414                $f_tpl->parseCurrentBlock();
415            }
416        } elseif ($quota_exceeded) {
417            return $quota_exceeded;
418        }
419
420        $pending = $this->getPending();
421        if ($pending) {
422            $f_tpl->setCurrentBlock("pending");
423            $f_tpl->setVariable("TXT_PENDING", $lng->txt("file_upload_pending") .
424                ": " . $pending);
425            $f_tpl->parseCurrentBlock();
426        }
427
428        if ($this->getDisabled() || $quota_exceeded) {
429            $f_tpl->setVariable(
430                "DISABLED",
431                " disabled=\"disabled\""
432            );
433        }
434
435        $f_tpl->setVariable("POST_VAR", $this->getPostVar());
436        $f_tpl->setVariable("ID", $this->getFieldId());
437        $f_tpl->setVariable("SIZE", $this->getSize());
438
439
440        /* experimental: bootstrap'ed file upload */
441        $f_tpl->setVariable("TXT_BROWSE", $lng->txt("select_file"));
442
443
444        return $f_tpl->get();
445    }
446
447    /**
448    * Insert property html
449    *
450    * @return	int	Size
451    */
452    public function insert($a_tpl)
453    {
454        $html = $this->render();
455
456        $a_tpl->setCurrentBlock("prop_generic");
457        $a_tpl->setVariable("PROP_GENERIC", $html);
458        $a_tpl->parseCurrentBlock();
459    }
460
461
462    protected function outputSuffixes($a_tpl, $a_block = "allowed_suffixes")
463    {
464        $lng = $this->lng;
465
466        if (is_array($this->getSuffixes()) && count($this->getSuffixes()) > 0) {
467            $suff_str = $delim = "";
468            foreach ($this->getSuffixes() as $suffix) {
469                $suff_str .= $delim . "." . $suffix;
470                $delim = ", ";
471            }
472            $a_tpl->setCurrentBlock($a_block);
473            $a_tpl->setVariable(
474                "TXT_ALLOWED_SUFFIXES",
475                $lng->txt("file_allowed_suffixes") . " " . $suff_str
476            );
477            $a_tpl->parseCurrentBlock();
478        }
479    }
480
481    protected function getMaxFileSizeString()
482    {
483        // get the value for the maximal uploadable filesize from the php.ini (if available)
484        $umf = ini_get("upload_max_filesize");
485        // get the value for the maximal post data from the php.ini (if available)
486        $pms = ini_get("post_max_size");
487
488        //convert from short-string representation to "real" bytes
489        $multiplier_a = array("K" => 1024, "M" => 1024 * 1024, "G" => 1024 * 1024 * 1024);
490
491        $umf_parts = preg_split("/(\d+)([K|G|M])/", $umf, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
492        $pms_parts = preg_split("/(\d+)([K|G|M])/", $pms, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
493
494        if (count($umf_parts) == 2) {
495            $umf = $umf_parts[0] * $multiplier_a[$umf_parts[1]];
496        }
497        if (count($pms_parts) == 2) {
498            $pms = $pms_parts[0] * $multiplier_a[$pms_parts[1]];
499        }
500
501        // use the smaller one as limit
502        $max_filesize = min($umf, $pms);
503
504        if (!$max_filesize) {
505            $max_filesize = max($umf, $pms);
506        }
507
508        //format for display in mega-bytes
509        $max_filesize = sprintf("%.1f MB", $max_filesize / 1024 / 1024);
510
511        return $max_filesize;
512    }
513
514    /**
515     * Get number of maximum file uploads as declared in php.ini
516     *
517     * @return int
518     */
519    protected function getMaxFileUploads()
520    {
521        return (int) ini_get("max_file_uploads");
522    }
523
524    /**
525    * Get deletion flag
526    */
527    public function getDeletionFlag()
528    {
529        if ($_POST[$this->getPostVar() . "_delete"]) {
530            return true;
531        }
532        return false;
533    }
534
535    /**
536    * Get HTML for toolbar
537    */
538    public function getToolbarHTML()
539    {
540        $html = $this->render("toolbar");
541        return $html;
542    }
543
544    public static function setPersonalWorkspaceQuotaCheck($a_value)
545    {
546        if ((bool) $a_value) {
547            if (ilDiskQuotaActivationChecker::_isPersonalWorkspaceActive()) {
548                self::$check_wsp_quota = true;
549                return;
550            }
551        }
552        self::$check_wsp_quota = false;
553    }
554}
555