FusionDirectory
class_FileAttribute.inc
1 <?php
2 /*
3  This code is part of FusionDirectory (http://www.fusiondirectory.org/)
4  Copyright (C) 2012-2016 FusionDirectory
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10 
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
19 */
20 
25 {
26  protected $binary = TRUE;
27 
28  function loadPostValue ()
29  {
30  $this->postValue = $this->value;
31  if (!empty($_FILES[$this->getHtmlId()]['name']) && $this->isVisible()) {
32  if ($_FILES[$this->getHtmlId()]['size'] <= 0) {
33  $error = new SimplePluginError(
34  $this,
35  htmlescape(sprintf(
36  _('Cannot read uploaded file: %s'),
37  _('file is empty')
38  ))
39  );
40  $error->display();
41  } elseif (!file_exists($_FILES[$this->getHtmlId()]['tmp_name'])) {
42  // Is there a tmp file, which we can use ?
43  $error = new SimplePluginError(
44  $this,
45  htmlescape(sprintf(
46  _('Cannot read uploaded file: %s'),
47  _('file not found')
48  ))
49  );
50  $error->display();
51  } elseif (!$handle = @fopen($_FILES[$this->getHtmlId()]['tmp_name'], 'r')) {
52  // Can we open the tmp file, for reading
53  $error = new SimplePluginError(
54  $this,
55  htmlescape(sprintf(
56  _('Cannot read uploaded file: %s'),
57  _('file not readable')
58  ))
59  );
60  $error->display();
61  } else {
62  // Everything just fine :)
63 
64  // Reading content
65  $this->readFile($handle);
66  }
67  // so that we only handle the file once
68  $_FILES[$this->getHtmlId()]['name'] = "";
69  }
70  }
71 
76  function readFile ($handle)
77  {
78  $postValue = fread($handle, 1024);
79  while (!feof($handle)) {
80  $postValue .= fread($handle, 1024);
81  }
82  $this->setPostValue($postValue);
83  @fclose($handle);
84  }
85 
86  function renderFormInput (): string
87  {
88  $id = $this->getHtmlId();
89  $display = $this->renderInputField('file', $id);
90  return $this->renderAcl($display);
91  }
92 
93  function displayValue ($value): string
94  {
95  return sprintf(_('%s (%d bytes)'), $this->getLabel(), mb_strlen($value, '8bit'));
96  }
97 
103  function serializeAttribute (array &$attributes, bool $form = TRUE)
104  {
105  if (!$form || $this->visible) {
106  parent::serializeAttribute($attributes, $form);
107 
108  if ($this->binary) {
109  $attributes[$this->getLdapName()]['binary'] = TRUE;
110  }
111  }
112  }
113 
118  function serializeValue ($value = NULL)
119  {
120  if ($value === NULL) {
121  $value = $this->getValue();
122  }
123  if ($this->binary) {
124  return base64_encode($value);
125  } else {
126  return $value;
127  }
128  }
129 
134  function deserializeValue ($value)
135  {
136  if ($this->disabled) {
137  return new SimplePluginError(
138  $this,
139  htmlescape(sprintf(_('Attribute %s is disabled, its value could not be set'), $this->getLdapName()))
140  );
141  }
142  if ($this->binary) {
143  $data = base64_decode($value, TRUE);
144  if ($data === FALSE) {
145  return new SimplePluginError(
146  $this,
147  htmlescape(_('Invalid base64 data'))
148  );
149  }
150  $this->setValue($data);
151  } else {
152  $this->setValue($value);
153  }
154  }
155 }
156 
161 {
162  protected $extension;
163  protected $upload;
164  protected $download = TRUE;
165 
166  function __construct ($label, $description, $ldapName, $required = FALSE, $extension = '', $upload = FALSE, $defaultValue = "", $acl = "")
167  {
168  parent::__construct($label, $description, $ldapName, $required, $defaultValue, $acl);
169  $this->extension = $extension;
170  $this->upload = $upload;
171  $this->binary = ($extension != '.txt');
172  }
173 
174  function computeFilename ()
175  {
176  return $this->getLdapName().$this->extension;
177  }
178 
179  function loadPostValue ()
180  {
181  if ($this->isVisible()) {
182  $this->postValue = $this->value;
183  if ($this->download) {
184  foreach (array_keys($_POST) as $name) {
185  if (preg_match('/^download'.$this->getHtmlId().'/', $name)) {
186  session::set('binary', $this->value);
187  session::set('binarytype', 'octet-stream');
188  session::set('binaryfile', $this->computeFilename());
189  header('location: getbin.php');
190  exit();
191  }
192  }
193  }
194  if ($this->upload && isset($_POST['upload'.$this->getHtmlId()])) {
195  parent::loadPostValue();
196  }
197  }
198  }
199 
200  function renderFormInput (): string
201  {
202  $id = $this->getHtmlId();
203  $display = '';
204  if ($this->upload) {
205  $display .= $this->renderInputField('file', $id);
206  $display .= $this->renderInputField('submit', 'upload'.$id, ['value' => _('Upload'), 'formnovalidate' => 'formnovalidate']);
207  }
208  if ($this->download) {
209  $display .= $this->renderInputField(
210  'image', 'download'.$id,
211  [
212  'title' => _('Download'),
213  'alt' => _('Download'),
214  'class' => 'center',
215  'src' => 'geticon.php?context=actions&icon=document-save&size=16',
216  ]
217  );
218  }
219  return $this->renderAcl($display);
220  }
221 
222  public function htmlIds (): array
223  {
224  $id = $this->getHtmlId();
225  $ids = [];
226  if ($this->download) {
227  $ids[] = 'download'.$id;
228  }
229  if ($this->upload) {
230  $ids[] = $id;
231  $ids[] = 'upload'.$id;
232  }
233  return $ids;
234  }
235 
236  function renderAttribute (array &$attributes, bool $readOnly, bool $readable, bool $writable)
237  {
238  if ($this->upload === FALSE) {
239  parent::renderAttribute($attributes, FALSE, $readable, $writable);
240  } else {
241  parent::renderAttribute($attributes, $readOnly, $readable, $writable);
242  }
243  }
244 }
245 
250 {
251  /* Default values are not the same that for FileDownloadAttribute */
252  function __construct ($label, $description, $ldapName, $required = FALSE, $extension = '.txt', $upload = TRUE, $download = TRUE, $defaultValue = '', $acl = '')
253  {
254  parent::__construct(
255  $label, $description, $ldapName, $required,
256  $extension, $upload, $defaultValue, $acl
257  );
258  $this->download = $download;
259  }
260 
263  function loadPostValue ()
264  {
265  if ($this->isVisible()) {
266  $this->postValue = $this->value;
267  if ($this->download) {
268  foreach (array_keys($_POST) as $name) {
269  if (preg_match('/^download'.$this->getHtmlId().'/', $name)) {
270  session::set('binary', $this->value);
271  session::set('binarytype', 'octet-stream');
272  session::set('binaryfile', $this->computeFilename());
273  header('location: getbin.php');
274  exit();
275  }
276  }
277  }
278  if ($this->upload) {
279  if (isset($_POST['upload'.$this->getHtmlId()])) {
280  parent::loadPostValue();
281  } else {
282  $id = $this->getHtmlId().'_text';
283  if (isset($_POST[$id])) {
284  $this->setPostValue($_POST[$id]);
285  }
286  }
287  }
288  }
289  }
290 
291  function fixPostValue ($value)
292  {
293  /* Replace CRLF by LF, to avoid non-ASCII chars */
294  return str_replace(["\r\n", "\r"], "\n", $value);
295  }
296 
297  function renderFormInput (): string
298  {
299  $id = $this->getHtmlId();
300  $display = '<textarea name="'.$id.'_text" id="'.$id.'_text"'.
301  ($this->disabled ? 'disabled="disabled"' : '').'>'.
302  '{literal}'.htmlescape($this->getValue()).'{/literal}</textarea><br/>';
303  return $this->renderAcl($display).parent::renderFormInput();
304  }
305 
306  public function htmlIds (): array
307  {
308  $id = $this->getHtmlId();
309  $ids = parent::htmlIds();
310  $ids[] = $id.'_text';
311  return $ids;
312  }
313 }
314 
319 {
320  protected $width;
321  protected $height;
322  protected $format;
323  protected $forceSize;
324  protected $placeholder;
325 
326  protected $imagickException;
327 
328  function __construct ($label, $description, $ldapName, $required = FALSE, $width = 48, $height = 48, $format = 'png', $forceSize = FALSE, $defaultValue = "", $acl = "")
329  {
330  parent::__construct($label, $description, $ldapName, $required, $defaultValue, $acl);
331  $this->width = $width;
332  $this->height = $height;
333  $this->format = $format;
334  $this->forceSize = $forceSize;
335  }
336 
337  function setPlaceholder ($placeholder)
338  {
339  $this->placeholder = $placeholder;
340  }
341 
344  function loadPostValue ()
345  {
346  $this->postValue = $this->value;
347  $id = $this->getHtmlId();
348  if (!$this->disabled && $this->isVisible()) {
349  foreach (array_keys($_POST) as $name) {
350  if (!$this->isRequired() && preg_match('/^'.$id.'_remove_/', $name)) {
351  $this->setPostValue('');
352  break;
353  }
354  if (preg_match('/^'.$id.'_upload_/', $name)) {
355  parent::loadPostValue();
356  break;
357  }
358  }
359  }
360  }
361 
362  function setValue ($value)
363  {
364  $this->imagickException = NULL;
365  if ($value == '') {
366  $this->value = '';
367  return;
368  }
369  if (class_exists('Imagick')) {
370  try {
371  $im = new Imagick();
372  $modify = FALSE;
373  $im->readImageBlob($value);
374 
375  $size = $im->getImageGeometry();
376 
377  if (
378  ($size['width'] > 0 && $size['height'] > 0) &&
379  (
380  ($size['width'] < $this->width && $size['height'] < $this->height) ||
381  ($size['width'] > $this->width) ||
382  ($size['height'] > $this->height)
383  )
384  ) {
385  $modify = TRUE;
386  $im->resizeImage($this->width, $this->height, Imagick::FILTER_GAUSSIAN, 1, !$this->forceSize);
387  }
388 
389  if ($modify || !preg_match('/^'.$this->format.'$/i', $im->getImageFormat())) {
390  if ($this->format == 'jpeg') {
391  $im->setImageCompression(Imagick::COMPRESSION_JPEG);
392  $im->setImageCompressionQuality(90);
393  }
394  $im->setImageFormat($this->format);
395 
396  /* Save attribute */
397  $this->value = $im->getImageBlob();
398  } else {
399  $this->value = $value;
400  }
401  } catch (ImagickException $e) {
402  /* Store the exception to return it in deserializeValue() */
403  $this->imagickException = new SimplePluginError(
404  $this,
405  SimplePluginCheckError::invalidValue($e->getMessage()),
406  0,
407  $e
408  );
409  $this->imagickException->display();
410  }
411  } else {
412  $error = new SimplePluginError(
413  $this,
414  htmlescape(_('Cannot save user picture, FusionDirectory requires the PHP module "imagick" to be installed!'))
415  );
416  $error->display();
417  }
418  }
419 
424  function deserializeValue ($value)
425  {
426  $error = parent::deserializeValue($value);
427  if (!empty($error)) {
428  return $error;
429  }
430  if ($this->imagickException !== NULL) {
431  return $this->imagickException;
432  }
433  }
434 
435  function renderFormInput (): string
436  {
437  $this->setValue($this->inputValue($this->getValue()));
438  $id = $this->getHtmlId();
439  // Just to be sure the image is not cached
440  $key = $this->getLdapName().random_int(0, 10000);
441  $display = '<img id="'.$id.'_img"'.
442  ($this->disabled ? 'disabled="disabled"' : '').
443  ' src="getbin.php?key='.$key.'"'.
444  ' style="border:1px solid black;"'.
445  ' alt="'.htmlescape($this->getDescription()).'"'.
446  ' title="'.htmlescape($this->getDescription()).'"'.
447  ' /><br/>';
448  $display .= $this->renderInputField('file', $id);
449  $display .= $this->renderInputField(
450  'image', $id.'_upload',
451  [
452  'class' => 'center',
453  'src' => 'geticon.php?context=actions&icon=upload&size=16',
454  'title' => _('Upload'),
455  'alt' => _('Upload')
456  ]
457  );
458  if (!$this->isRequired()) {
459  $display .= $this->renderInputField(
460  'image', $id.'_remove',
461  [
462  'class' => 'center',
463  'src' => 'geticon.php?context=actions&icon=remove&size=16',
464  'title' => _('Remove'),
465  'alt' => _('Remove')
466  ]
467  );
468  }
469  if (($this->getValue() == '') && ($this->placeholder != '')) {
470  session::set('binary'.$key, $this->placeholder);
471  } else {
472  session::set('binary'.$key, $this->getValue());
473  }
474  session::set('binarytype', 'image/'.$this->format);
475  return $this->renderAcl($display);
476  }
477 
478  public function htmlIds (): array
479  {
480  $id = $this->getHtmlId();
481  return [$id.'_img',$id,'upload'.$id];
482  }
483 
486  function fillLdapValue (array &$attrs)
487  {
488  if ($this->isInLdap()) {
489  $value = $this->computeLdapValue();
490  if ($value !== '') {
491  if ($this->isTemplate()) {
492  /* Add %% to provide template from parsing binary string */
493  $value = '%%'.$value;
494  }
495  $attrs[$this->getLdapName()] = $value;
496  } else {
497  $attrs[$this->getLdapName()] = [];
498  }
499  }
500  }
501 
502  function inputValue ($value)
503  {
504  /* Remove %% that might be there in case of templating */
505  return preg_replace('/^%%/', '', $value);
506  }
507 }
serializeValue($value=NULL)
Serialize value for RPC requests.
htmlescape(string $str)
Escape string for HTML output.
Definition: php_setup.inc:32
deserializeValue($value)
Apply value from RPC requests.
deserializeValue($value)
Apply value from RPC requests.
FileAttribue with a download button.
loadPostValue()
Update this attributes postValue depending of the $_POST values.
readFile($handle)
This function read the file from the given handle and then closes it.
Error returned by any method of SimplePlugin.
static set($name, $value)
Set a value in a session.
serializeAttribute(array &$attributes, bool $form=TRUE)
Serialize this attribute for RPC requests.
fixPostValue($value)
In case a treatment is needed on POST content.
static invalidValue(string $error)
Format error message for invalid value.
Attribute for storing an image.
fillLdapValue(array &$attrs)
Fill LDAP value in the attrs array.
renderAttribute(array &$attributes, bool $readOnly, bool $readable, bool $writable)
Render this attribute form input(s)
renderAcl(string $display)
Add ACL information around display.
A FileDownloadAttribute which displays a text area to edit the value.
inputValue($ldapValue)
Return the ldap value in the correct intern format value.
This class allow to handle easily an File LDAP attribute.
This class allow to handle easily any kind of LDAP attribute.
loadPostValue()
Update this attributes postValue depending of the $_POST values.
__construct(string $label, string $description, string $ldapName, bool $required=FALSE, $defaultValue='', string $acl='')
The constructor of Attribute.