Added the zend framework 2 library, the path is specified in line no.26 in zend_modul...
[openemr.git] / interface / modules / zend_modules / library / Zend / File / Transfer / Adapter / AbstractAdapter.php
blob0bec4da1a8366eccde2098ab8152b2e13d5fe57b
1 <?php
2 /**
3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2013 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
8 */
10 namespace Zend\File\Transfer\Adapter;
12 use ErrorException;
13 use Zend\File\Transfer;
14 use Zend\File\Transfer\Exception;
15 use Zend\Filter;
16 use Zend\Filter\Exception as FilterException;
17 use Zend\I18n\Translator\Translator;
18 use Zend\I18n\Translator\TranslatorAwareInterface;
19 use Zend\Stdlib\ErrorHandler;
20 use Zend\Validator;
22 /**
23 * Abstract class for file transfers (Downloads and Uploads)
25 * This class needs a full rewrite. It re-implements functionality present in
26 * Zend\Filter\Input and/or Zend\Form\Element, and in a way that's inconsistent
27 * with either one. Additionally, plugin loader usage is now deprecated -- but
28 * modifying that should be done in tandem with a rewrite to utilize validator
29 * and filter chains instead.
31 * @todo Rewrite
33 abstract class AbstractAdapter implements TranslatorAwareInterface
35 /**@+
36 * Plugin loader Constants
38 const FILTER = 'FILTER';
39 const VALIDATOR = 'VALIDATOR';
40 /**@-*/
42 /**
43 * Internal list of breaks
45 * @var array
47 protected $break = array();
49 /**
50 * @var FilterPluginManager
52 protected $filterManager;
54 /**
55 * Internal list of filters
57 * @var array
59 protected $filters = array();
61 /**
62 * Plugin loaders for filter and validation chains
64 * @var array
66 protected $loaders = array();
68 /**
69 * Internal list of messages
71 * @var array
73 protected $messages = array();
75 /**
76 * @var Translator
78 protected $translator;
80 /**
81 * Is translation enabled?
83 * @var bool
85 protected $translatorEnabled = true;
87 /**
88 * Translator text domain (optional)
90 * @var string
92 protected $translatorTextDomain = 'default';
94 /**
95 * @var ValidatorPluginManager
97 protected $validatorManager;
99 /**
100 * Internal list of validators
101 * @var array
103 protected $validators = array();
106 * Internal list of files
107 * This array looks like this:
108 * array(form => array( - Form is the name within the form or, if not set the filename
109 * name, - Original name of this file
110 * type, - Mime type of this file
111 * size, - Filesize in bytes
112 * tmp_name, - Internally temporary filename for uploaded files
113 * error, - Error which has occurred
114 * destination, - New destination for this file
115 * validators, - Set validator names for this file
116 * files - Set file names for this file
117 * ))
119 * @var array
121 protected $files = array();
124 * TMP directory
125 * @var string
127 protected $tmpDir;
130 * Available options for file transfers
132 protected $options = array(
133 'ignoreNoFile' => false,
134 'useByteString' => true,
135 'magicFile' => null,
136 'detectInfos' => true,
140 * Send file
142 * @param mixed $options
143 * @return bool
145 abstract public function send($options = null);
148 * Receive file
150 * @param mixed $options
151 * @return bool
153 abstract public function receive($options = null);
156 * Is file sent?
158 * @param array|string|null $files
159 * @return bool
161 abstract public function isSent($files = null);
164 * Is file received?
166 * @param array|string|null $files
167 * @return bool
169 abstract public function isReceived($files = null);
172 * Has a file been uploaded ?
174 * @param array|string|null $files
175 * @return bool
177 abstract public function isUploaded($files = null);
180 * Has the file been filtered ?
182 * @param array|string|null $files
183 * @return bool
185 abstract public function isFiltered($files = null);
188 * Adds one or more files
190 * @param string|array $file File to add
191 * @param string|array $validator Validators to use for this file, must be set before
192 * @param string|array $filter Filters to use for this file, must be set before
193 * @return AbstractAdapter
194 * @throws Exception Not implemented
196 //abstract public function addFile($file, $validator = null, $filter = null);
199 * Returns all set types
201 * @return array List of set types
202 * @throws Exception Not implemented
204 //abstract public function getType();
207 * Adds one or more type of files
209 * @param string|array $type Type of files to add
210 * @param string|array $validator Validators to use for this file, must be set before
211 * @param string|array $filter Filters to use for this file, must be set before
212 * @return AbstractAdapter
213 * @throws Exception Not implemented
215 //abstract public function addType($type, $validator = null, $filter = null);
218 * Returns all set files
220 * @return array List of set files
222 //abstract public function getFile();
225 * Set the filter plugin manager instance
227 * @param FilterPluginManager $filterManager
228 * @return AbstractAdapter
230 public function setFilterManager(FilterPluginManager $filterManager)
232 $this->filterManager = $filterManager;
233 return $this;
237 * Get the filter plugin manager instance
239 * @return FilterPluginManager
241 public function getFilterManager()
243 if (!$this->filterManager instanceof FilterPluginManager) {
244 $this->setFilterManager(new FilterPluginManager());
246 return $this->filterManager;
250 * Set the validator plugin manager instance
252 * @param ValidatorPluginManager $validatorManager
253 * @return AbstractAdapter
255 public function setValidatorManager(ValidatorPluginManager $validatorManager)
257 $this->validatorManager = $validatorManager;
258 return $this;
262 * Get the validator plugin manager instance
264 * @return ValidatorPluginManager
266 public function getValidatorManager()
268 if (!$this->validatorManager instanceof ValidatorPluginManager) {
269 $this->setValidatorManager(new ValidatorPluginManager());
271 return $this->validatorManager;
275 * Adds a new validator for this class
277 * @param string|Validator\ValidatorInterface $validator Type of validator to add
278 * @param bool $breakChainOnFailure If the validation chain should stop an failure
279 * @param string|array $options Options to set for the validator
280 * @param string|array $files Files to limit this validator to
281 * @return AbstractAdapter
282 * @throws Exception\InvalidArgumentException for invalid type
284 public function addValidator($validator, $breakChainOnFailure = false, $options = null, $files = null)
286 if (is_string($validator)) {
287 $validator = $this->getValidatorManager()->get($validator, $options);
288 if (is_array($options) && isset($options['messages'])) {
289 if (is_array($options['messages'])) {
290 $validator->setMessages($options['messages']);
291 } elseif (is_string($options['messages'])) {
292 $validator->setMessage($options['messages']);
295 unset($options['messages']);
299 if (!$validator instanceof Validator\ValidatorInterface) {
300 throw new Exception\InvalidArgumentException(
301 'Invalid validator provided to addValidator; ' .
302 'must be string or Zend\Validator\ValidatorInterface'
306 $name = get_class($validator);
308 $this->validators[$name] = $validator;
309 $this->break[$name] = $breakChainOnFailure;
310 $files = $this->getFiles($files, true, true);
311 foreach ($files as $file) {
312 if ($name == 'NotEmpty') {
313 $temp = $this->files[$file]['validators'];
314 $this->files[$file]['validators'] = array($name);
315 $this->files[$file]['validators'] += $temp;
316 } else {
317 $this->files[$file]['validators'][] = $name;
320 $this->files[$file]['validated'] = false;
323 return $this;
327 * Add Multiple validators at once
329 * @param array $validators
330 * @param string|array $files
331 * @return AbstractAdapter
332 * @throws Exception\InvalidArgumentException for invalid type
334 public function addValidators(array $validators, $files = null)
336 foreach ($validators as $name => $validatorInfo) {
337 if ($validatorInfo instanceof Validator\ValidatorInterface) {
338 $this->addValidator($validatorInfo, null, null, $files);
339 } elseif (is_string($validatorInfo)) {
340 if (!is_int($name)) {
341 $this->addValidator($name, null, $validatorInfo, $files);
342 } else {
343 $this->addValidator($validatorInfo, null, null, $files);
345 } elseif (is_array($validatorInfo)) {
346 $argc = count($validatorInfo);
347 $breakChainOnFailure = false;
348 $options = array();
349 if (isset($validatorInfo['validator'])) {
350 $validator = $validatorInfo['validator'];
351 if (isset($validatorInfo['breakChainOnFailure'])) {
352 $breakChainOnFailure = $validatorInfo['breakChainOnFailure'];
355 if (isset($validatorInfo['options'])) {
356 $options = $validatorInfo['options'];
359 $this->addValidator($validator, $breakChainOnFailure, $options, $files);
360 } else {
361 if (is_string($name)) {
362 $validator = $name;
363 $options = $validatorInfo;
364 $this->addValidator($validator, $breakChainOnFailure, $options, $files);
365 } else {
366 $file = $files;
367 switch (true) {
368 case (0 == $argc):
369 break;
370 case (1 <= $argc):
371 $validator = array_shift($validatorInfo);
372 case (2 <= $argc):
373 $breakChainOnFailure = array_shift($validatorInfo);
374 case (3 <= $argc):
375 $options = array_shift($validatorInfo);
376 case (4 <= $argc):
377 if (!empty($validatorInfo)) {
378 $file = array_shift($validatorInfo);
380 default:
381 $this->addValidator($validator, $breakChainOnFailure, $options, $file);
382 break;
386 } else {
387 throw new Exception\InvalidArgumentException('Invalid validator passed to addValidators()');
391 return $this;
395 * Sets a validator for the class, erasing all previous set
397 * @param array $validators Validators to set
398 * @param string|array $files Files to limit this validator to
399 * @return AbstractAdapter
401 public function setValidators(array $validators, $files = null)
403 $this->clearValidators();
404 return $this->addValidators($validators, $files);
408 * Determine if a given validator has already been registered
410 * @param string $name
411 * @return bool
413 public function hasValidator($name)
415 return (false !== $this->getValidatorIdentifier($name));
419 * Retrieve individual validator
421 * @param string $name
422 * @return Validator\ValidatorInterface|null
424 public function getValidator($name)
426 if (false === ($identifier = $this->getValidatorIdentifier($name))) {
427 return null;
429 return $this->validators[$identifier];
433 * Returns all set validators
435 * @param string|array $files (Optional) Returns the validator for this files
436 * @return null|array List of set validators
438 public function getValidators($files = null)
440 if ($files == null) {
441 return $this->validators;
444 $files = $this->getFiles($files, true, true);
445 $validators = array();
446 foreach ($files as $file) {
447 if (!empty($this->files[$file]['validators'])) {
448 $validators += $this->files[$file]['validators'];
452 $validators = array_unique($validators);
453 $result = array();
454 foreach ($validators as $validator) {
455 $result[$validator] = $this->validators[$validator];
458 return $result;
462 * Remove an individual validator
464 * @param string $name
465 * @return AbstractAdapter
467 public function removeValidator($name)
469 if (false === ($key = $this->getValidatorIdentifier($name))) {
470 return $this;
473 unset($this->validators[$key]);
474 foreach (array_keys($this->files) as $file) {
475 if (empty($this->files[$file]['validators'])) {
476 continue;
479 $index = array_search($key, $this->files[$file]['validators']);
480 if ($index === false) {
481 continue;
484 unset($this->files[$file]['validators'][$index]);
485 $this->files[$file]['validated'] = false;
488 return $this;
492 * Remove all validators
494 * @return AbstractAdapter
496 public function clearValidators()
498 $this->validators = array();
499 foreach (array_keys($this->files) as $file) {
500 $this->files[$file]['validators'] = array();
501 $this->files[$file]['validated'] = false;
504 return $this;
508 * Sets Options for adapters
510 * @param array $options Options to set
511 * @param array $files (Optional) Files to set the options for
512 * @return AbstractAdapter
514 public function setOptions($options = array(), $files = null)
516 $file = $this->getFiles($files, false, true);
518 if (is_array($options)) {
519 if (empty($file)) {
520 $this->options = array_merge($this->options, $options);
523 foreach ($options as $name => $value) {
524 foreach ($file as $key => $content) {
525 switch ($name) {
526 case 'magicFile' :
527 $this->files[$key]['options'][$name] = (string) $value;
528 break;
530 case 'ignoreNoFile' :
531 case 'useByteString' :
532 case 'detectInfos' :
533 $this->files[$key]['options'][$name] = (bool) $value;
534 break;
536 default:
537 continue;
543 return $this;
547 * Returns set options for adapters or files
549 * @param array $files (Optional) Files to return the options for
550 * @return array Options for given files
552 public function getOptions($files = null)
554 $file = $this->getFiles($files, false, true);
556 foreach ($file as $key => $content) {
557 if (isset($this->files[$key]['options'])) {
558 $options[$key] = $this->files[$key]['options'];
559 } else {
560 $options[$key] = array();
564 return $options;
568 * Checks if the files are valid
570 * @param string|array $files (Optional) Files to check
571 * @return bool True if all checks are valid
573 public function isValid($files = null)
575 $check = $this->getFiles($files, false, true);
576 if (empty($check)) {
577 return false;
580 $translator = $this->getTranslator();
581 $this->messages = array();
582 $break = false;
583 foreach ($check as $content) {
584 if (array_key_exists('validators', $content) &&
585 in_array('Zend\Validator\File\Count', $content['validators'])) {
586 $validator = $this->validators['Zend\Validator\File\Count'];
587 $count = $content;
588 if (empty($content['tmp_name'])) {
589 continue;
592 if (array_key_exists('destination', $content)) {
593 $checkit = $content['destination'];
594 } else {
595 $checkit = dirname($content['tmp_name']);
598 $checkit .= DIRECTORY_SEPARATOR . $content['name'];
599 $validator->addFile($checkit);
603 if (isset($count)) {
604 if (!$validator->isValid($count['tmp_name'], $count)) {
605 $this->messages += $validator->getMessages();
609 foreach ($check as $key => $content) {
610 $fileerrors = array();
611 if (array_key_exists('validators', $content) && $content['validated']) {
612 continue;
615 if (array_key_exists('validators', $content)) {
616 foreach ($content['validators'] as $class) {
617 $validator = $this->validators[$class];
618 if (method_exists($validator, 'setTranslator')) {
619 $validator->setTranslator($translator);
622 if (($class === 'Zend\Validator\File\Upload') && (empty($content['tmp_name']))) {
623 $tocheck = $key;
624 } else {
625 $tocheck = $content['tmp_name'];
628 if (!$validator->isValid($tocheck, $content)) {
629 $fileerrors += $validator->getMessages();
632 if (!empty($content['options']['ignoreNoFile']) && (isset($fileerrors['fileUploadErrorNoFile']))) {
633 unset($fileerrors['fileUploadErrorNoFile']);
634 break;
637 if (($class === 'Zend\Validator\File\Upload') && (count($fileerrors) > 0)) {
638 break;
641 if (($this->break[$class]) && (count($fileerrors) > 0)) {
642 $break = true;
643 break;
648 if (count($fileerrors) > 0) {
649 $this->files[$key]['validated'] = false;
650 } else {
651 $this->files[$key]['validated'] = true;
654 $this->messages += $fileerrors;
655 if ($break) {
656 break;
660 if (count($this->messages) > 0) {
661 return false;
664 return true;
668 * Returns found validation messages
670 * @return array
672 public function getMessages()
674 return $this->messages;
678 * Retrieve error codes
680 * @return array
682 public function getErrors()
684 return array_keys($this->messages);
688 * Are there errors registered?
690 * @return bool
692 public function hasErrors()
694 return (!empty($this->messages));
698 * Adds a new filter for this class
700 * @param string|Filter\FilterInterface $filter Type of filter to add
701 * @param string|array $options Options to set for the filter
702 * @param string|array $files Files to limit this filter to
703 * @return AbstractAdapter
704 * @throws Exception\InvalidArgumentException for invalid type
706 public function addFilter($filter, $options = null, $files = null)
708 if (is_string($filter)) {
709 $filter = $this->getFilterManager()->get($filter, $options);
712 if (!$filter instanceof Filter\FilterInterface) {
713 throw new Exception\InvalidArgumentException('Invalid filter specified');
716 $class = get_class($filter);
717 $this->filters[$class] = $filter;
718 $files = $this->getFiles($files, true, true);
719 foreach ($files as $file) {
720 $this->files[$file]['filters'][] = $class;
723 return $this;
727 * Add Multiple filters at once
729 * @param array $filters
730 * @param string|array $files
731 * @return AbstractAdapter
733 public function addFilters(array $filters, $files = null)
735 foreach ($filters as $key => $spec) {
736 if ($spec instanceof Filter\FilterInterface) {
737 $this->addFilter($spec, null, $files);
738 continue;
741 if (is_string($key)) {
742 $this->addFilter($key, $spec, $files);
743 continue;
746 if (is_int($key)) {
747 if (is_string($spec)) {
748 $this->addFilter($spec, null, $files);
749 continue;
752 if (is_array($spec)) {
753 if (!array_key_exists('filter', $spec)) {
754 continue;
757 $filter = $spec['filter'];
758 unset($spec['filter']);
759 $this->addFilter($filter, $spec, $files);
760 continue;
763 continue;
767 return $this;
771 * Sets a filter for the class, erasing all previous set
773 * @param array $filters Filter to set
774 * @param string|array $files Files to limit this filter to
775 * @return Filter\AbstractFilter
777 public function setFilters(array $filters, $files = null)
779 $this->clearFilters();
780 return $this->addFilters($filters, $files);
784 * Determine if a given filter has already been registered
786 * @param string $name
787 * @return bool
789 public function hasFilter($name)
791 return (false !== $this->getFilterIdentifier($name));
795 * Retrieve individual filter
797 * @param string $name
798 * @return Filter\FilterInterface|null
800 public function getFilter($name)
802 if (false === ($identifier = $this->getFilterIdentifier($name))) {
803 return null;
806 return $this->filters[$identifier];
810 * Returns all set filters
812 * @param string|array $files (Optional) Returns the filter for this files
813 * @return array List of set filters
814 * @throws Exception\RuntimeException When file not found
816 public function getFilters($files = null)
818 if ($files === null) {
819 return $this->filters;
822 $files = $this->getFiles($files, true, true);
823 $filters = array();
824 foreach ($files as $file) {
825 if (!empty($this->files[$file]['filters'])) {
826 $filters += $this->files[$file]['filters'];
830 $filters = array_unique($filters);
831 $result = array();
832 foreach ($filters as $filter) {
833 $result[] = $this->filters[$filter];
836 return $result;
840 * Remove an individual filter
842 * @param string $name
843 * @return AbstractAdapter
845 public function removeFilter($name)
847 if (false === ($key = $this->getFilterIdentifier($name))) {
848 return $this;
851 unset($this->filters[$key]);
852 foreach (array_keys($this->files) as $file) {
853 if (empty($this->files[$file]['filters'])) {
854 continue;
857 $index = array_search($key, $this->files[$file]['filters']);
858 if ($index === false) {
859 continue;
862 unset($this->files[$file]['filters'][$index]);
864 return $this;
868 * Remove all filters
870 * @return AbstractAdapter
872 public function clearFilters()
874 $this->filters = array();
875 foreach (array_keys($this->files) as $file) {
876 $this->files[$file]['filters'] = array();
879 return $this;
883 * Retrieves the filename of transferred files.
885 * @param string $file (Optional) Element to return the filename for
886 * @param bool $path (Optional) Should the path also be returned ?
887 * @return string|array
889 public function getFileName($file = null, $path = true)
891 $files = $this->getFiles($file, true, true);
892 $result = array();
893 $directory = "";
894 foreach ($files as $file) {
895 if (empty($this->files[$file]['name'])) {
896 continue;
899 if ($path === true) {
900 $directory = $this->getDestination($file) . DIRECTORY_SEPARATOR;
903 $result[$file] = $directory . $this->files[$file]['name'];
906 if (count($result) == 1) {
907 return current($result);
910 return $result;
914 * Retrieve additional internal file informations for files
916 * @param string $file (Optional) File to get informations for
917 * @return array
919 public function getFileInfo($file = null)
921 return $this->getFiles($file);
925 * Sets a new destination for the given files
927 * @deprecated Will be changed to be a filter!!!
928 * @param string $destination New destination directory
929 * @param string|array $files Files to set the new destination for
930 * @return AbstractAdapter
931 * @throws Exception\InvalidArgumentException when the given destination is not a directory or does not exist
933 public function setDestination($destination, $files = null)
935 $orig = $files;
936 $destination = rtrim($destination, "/\\");
937 if (!is_dir($destination)) {
938 throw new Exception\InvalidArgumentException('The given destination is not a directory or does not exist');
941 if (!is_writable($destination)) {
942 throw new Exception\InvalidArgumentException('The given destination is not writeable');
945 if ($files === null) {
946 foreach ($this->files as $file => $content) {
947 $this->files[$file]['destination'] = $destination;
949 } else {
950 $files = $this->getFiles($files, true, true);
951 if (empty($files) and is_string($orig)) {
952 $this->files[$orig]['destination'] = $destination;
955 foreach ($files as $file) {
956 $this->files[$file]['destination'] = $destination;
960 return $this;
964 * Retrieve destination directory value
966 * @param null|string|array $files
967 * @throws Exception\InvalidArgumentException
968 * @return null|string|array
970 public function getDestination($files = null)
972 $orig = $files;
973 $files = $this->getFiles($files, false, true);
974 $destinations = array();
975 if (empty($files) and is_string($orig)) {
976 if (isset($this->files[$orig]['destination'])) {
977 $destinations[$orig] = $this->files[$orig]['destination'];
978 } else {
979 throw new Exception\InvalidArgumentException(
980 sprintf('The file transfer adapter can not find "%s"', $orig)
985 foreach ($files as $key => $content) {
986 if (isset($this->files[$key]['destination'])) {
987 $destinations[$key] = $this->files[$key]['destination'];
988 } else {
989 $tmpdir = $this->getTmpDir();
990 $this->setDestination($tmpdir, $key);
991 $destinations[$key] = $tmpdir;
995 if (empty($destinations)) {
996 $destinations = $this->getTmpDir();
997 } elseif (count($destinations) == 1) {
998 $destinations = current($destinations);
1001 return $destinations;
1005 * Sets translator to use in helper
1007 * @param Translator $translator [optional] translator.
1008 * Default is null, which sets no translator.
1009 * @param string $textDomain [optional] text domain
1010 * Default is null, which skips setTranslatorTextDomain
1011 * @return AbstractAdapter
1013 public function setTranslator(Translator $translator = null, $textDomain = null)
1015 $this->translator = $translator;
1016 if (null !== $textDomain) {
1017 $this->setTranslatorTextDomain($textDomain);
1019 return $this;
1023 * Retrieve localization translator object
1025 * @return Translator|null
1027 public function getTranslator()
1029 if ($this->isTranslatorEnabled()) {
1030 return null;
1033 return $this->translator;
1037 * Checks if the helper has a translator
1039 * @return bool
1041 public function hasTranslator()
1043 return (bool) $this->getTranslator();
1047 * Indicate whether or not translation should be enabled
1049 * @param bool $flag
1050 * @return AbstractAdapter
1052 public function setTranslatorEnabled($flag = true)
1054 $this->translatorEnabled = (bool) $flag;
1055 return $this;
1059 * Is translation enabled?
1061 * @return bool
1063 public function isTranslatorEnabled()
1065 return $this->translatorEnabled;
1069 * Set translation text domain
1071 * @param string $textDomain
1072 * @return AbstractAdapter
1074 public function setTranslatorTextDomain($textDomain = 'default')
1076 $this->translatorTextDomain = $textDomain;
1077 return $this;
1081 * Return the translation text domain
1083 * @return string
1085 public function getTranslatorTextDomain()
1087 return $this->translatorTextDomain;
1091 * Returns the hash for a given file
1093 * @param string $hash Hash algorithm to use
1094 * @param string|array $files Files to return the hash for
1095 * @return string|array Hashstring
1096 * @throws Exception\InvalidArgumentException On unknown hash algorithm
1098 public function getHash($hash = 'crc32', $files = null)
1100 if (!in_array($hash, hash_algos())) {
1101 throw new Exception\InvalidArgumentException('Unknown hash algorithm');
1104 $files = $this->getFiles($files);
1105 $result = array();
1106 foreach ($files as $key => $value) {
1107 if (file_exists($value['name'])) {
1108 $result[$key] = hash_file($hash, $value['name']);
1109 } elseif (file_exists($value['tmp_name'])) {
1110 $result[$key] = hash_file($hash, $value['tmp_name']);
1111 } elseif (empty($value['options']['ignoreNoFile'])) {
1112 throw new Exception\InvalidArgumentException("The file '{$value['name']}' does not exist");
1116 if (count($result) == 1) {
1117 return current($result);
1120 return $result;
1124 * Returns the real filesize of the file
1126 * @param string|array $files Files to get the filesize from
1127 * @return string|array Filesize
1128 * @throws Exception\InvalidArgumentException When the file does not exist
1130 public function getFileSize($files = null)
1132 $files = $this->getFiles($files);
1133 $result = array();
1134 foreach ($files as $key => $value) {
1135 if (file_exists($value['name']) || file_exists($value['tmp_name'])) {
1136 if ($value['options']['useByteString']) {
1137 $result[$key] = static::toByteString($value['size']);
1138 } else {
1139 $result[$key] = $value['size'];
1141 } elseif (empty($value['options']['ignoreNoFile'])) {
1142 throw new Exception\InvalidArgumentException("The file '{$value['name']}' does not exist");
1143 } else {
1144 continue;
1148 if (count($result) == 1) {
1149 return current($result);
1152 return $result;
1156 * Internal method to detect the size of a file
1158 * @param array $value File infos
1159 * @return string Filesize of given file
1161 protected function detectFileSize($value)
1163 if (file_exists($value['name'])) {
1164 $filename = $value['name'];
1165 } elseif (file_exists($value['tmp_name'])) {
1166 $filename = $value['tmp_name'];
1167 } else {
1168 return null;
1171 ErrorHandler::start();
1172 $filesize = filesize($filename);
1173 $return = ErrorHandler::stop();
1174 if ($return instanceof ErrorException) {
1175 $filesize = 0;
1178 return sprintf("%u", $filesize);
1182 * Returns the real mimetype of the file
1183 * Uses fileinfo, when not available mime_magic and as last fallback a manual given mimetype
1185 * @param string|array $files Files to get the mimetype from
1186 * @return string|array MimeType
1187 * @throws Exception\InvalidArgumentException When the file does not exist
1189 public function getMimeType($files = null)
1191 $files = $this->getFiles($files);
1192 $result = array();
1193 foreach ($files as $key => $value) {
1194 if (file_exists($value['name']) || file_exists($value['tmp_name'])) {
1195 $result[$key] = $value['type'];
1196 } elseif (empty($value['options']['ignoreNoFile'])) {
1197 throw new Exception\InvalidArgumentException("the file '{$value['name']}' does not exist");
1198 } else {
1199 continue;
1203 if (count($result) == 1) {
1204 return current($result);
1207 return $result;
1211 * Internal method to detect the mime type of a file
1213 * @param array $value File infos
1214 * @return string Mimetype of given file
1216 protected function detectMimeType($value)
1218 if (file_exists($value['name'])) {
1219 $file = $value['name'];
1220 } elseif (file_exists($value['tmp_name'])) {
1221 $file = $value['tmp_name'];
1222 } else {
1223 return null;
1226 if (class_exists('finfo', false)) {
1227 if (!empty($value['options']['magicFile'])) {
1228 ErrorHandler::start();
1229 $mime = finfo_open(FILEINFO_MIME_TYPE, $value['options']['magicFile']);
1230 ErrorHandler::stop();
1233 if (empty($mime)) {
1234 ErrorHandler::start();
1235 $mime = finfo_open(FILEINFO_MIME_TYPE);
1236 ErrorHandler::stop();
1239 if (!empty($mime)) {
1240 $result = finfo_file($mime, $file);
1243 unset($mime);
1246 if (empty($result) && (function_exists('mime_content_type')
1247 && ini_get('mime_magic.magicfile'))) {
1248 $result = mime_content_type($file);
1251 if (empty($result)) {
1252 $result = 'application/octet-stream';
1255 return $result;
1259 * Returns the formatted size
1261 * @param int $size
1262 * @return string
1264 protected static function toByteString($size)
1266 $sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
1267 for ($i=0; $size >= 1024 && $i < 9; $i++) {
1268 $size /= 1024;
1271 return round($size, 2) . $sizes[$i];
1275 * Internal function to filter all given files
1277 * @param string|array $files (Optional) Files to check
1278 * @return bool False on error
1280 protected function filter($files = null)
1282 $check = $this->getFiles($files);
1283 foreach ($check as $name => $content) {
1284 if (array_key_exists('filters', $content)) {
1285 foreach ($content['filters'] as $class) {
1286 $filter = $this->filters[$class];
1287 try {
1288 $result = $filter->filter($this->getFileName($name));
1290 $this->files[$name]['destination'] = dirname($result);
1291 $this->files[$name]['name'] = basename($result);
1292 } catch (FilterException\ExceptionInterface $e) {
1293 $this->messages += array($e->getMessage());
1299 if (count($this->messages) > 0) {
1300 return false;
1303 return true;
1307 * Determine system TMP directory and detect if we have read access
1309 * @return string
1310 * @throws Exception\RuntimeException if unable to determine directory
1312 protected function getTmpDir()
1314 if (null === $this->tmpDir) {
1315 $tmpdir = array();
1316 if (function_exists('sys_get_temp_dir')) {
1317 $tmpdir[] = sys_get_temp_dir();
1320 if (!empty($_ENV['TMP'])) {
1321 $tmpdir[] = realpath($_ENV['TMP']);
1324 if (!empty($_ENV['TMPDIR'])) {
1325 $tmpdir[] = realpath($_ENV['TMPDIR']);
1328 if (!empty($_ENV['TEMP'])) {
1329 $tmpdir[] = realpath($_ENV['TEMP']);
1332 $upload = ini_get('upload_tmp_dir');
1333 if ($upload) {
1334 $tmpdir[] = realpath($upload);
1337 foreach ($tmpdir as $directory) {
1338 if ($this->isPathWriteable($directory)) {
1339 $this->tmpDir = $directory;
1343 if (empty($this->tmpDir)) {
1344 // Attemp to detect by creating a temporary file
1345 $tempFile = tempnam(md5(uniqid(rand(), true)), '');
1346 if ($tempFile) {
1347 $this->tmpDir = realpath(dirname($tempFile));
1348 unlink($tempFile);
1349 } else {
1350 throw new Exception\RuntimeException('Could not determine a temporary directory');
1354 $this->tmpDir = rtrim($this->tmpDir, "/\\");
1356 return $this->tmpDir;
1360 * Tries to detect if we can read and write to the given path
1362 * @param string $path
1363 * @return bool
1365 protected function isPathWriteable($path)
1367 $tempFile = rtrim($path, "/\\");
1368 $tempFile .= '/' . 'test.1';
1370 ErrorHandler::start();
1371 $result = file_put_contents($tempFile, 'TEST');
1372 ErrorHandler::stop();
1374 if ($result == false) {
1375 return false;
1378 ErrorHandler::start();
1379 $result = unlink($tempFile);
1380 ErrorHandler::stop();
1382 if ($result == false) {
1383 return false;
1386 return true;
1390 * Returns found files based on internal file array and given files
1392 * @param string|array $files (Optional) Files to return
1393 * @param bool $names (Optional) Returns only names on true, else complete info
1394 * @param bool $noexception (Optional) Allows throwing an exception, otherwise returns an empty array
1395 * @return array Found files
1396 * @throws Exception\RuntimeException On false filename
1398 protected function getFiles($files, $names = false, $noexception = false)
1400 $check = array();
1402 if (is_string($files)) {
1403 $files = array($files);
1406 if (is_array($files)) {
1407 foreach ($files as $find) {
1408 $found = array();
1409 foreach ($this->files as $file => $content) {
1410 if (!isset($content['name'])) {
1411 continue;
1414 if (($content['name'] === $find) && isset($content['multifiles'])) {
1415 foreach ($content['multifiles'] as $multifile) {
1416 $found[] = $multifile;
1418 break;
1421 if ($file === $find) {
1422 $found[] = $file;
1423 break;
1426 if ($content['name'] === $find) {
1427 $found[] = $file;
1428 break;
1432 if (empty($found)) {
1433 if ($noexception !== false) {
1434 return array();
1437 throw new Exception\RuntimeException(sprintf('The file transfer adapter can not find "%s"', $find));
1440 foreach ($found as $checked) {
1441 $check[$checked] = $this->files[$checked];
1446 if ($files === null) {
1447 $check = $this->files;
1448 $keys = array_keys($check);
1449 foreach ($keys as $key) {
1450 if (isset($check[$key]['multifiles'])) {
1451 unset($check[$key]);
1456 if ($names) {
1457 $check = array_keys($check);
1460 return $check;
1464 * Retrieve internal identifier for a named validator
1466 * @param string $name
1467 * @return string
1469 protected function getValidatorIdentifier($name)
1471 if (array_key_exists($name, $this->validators)) {
1472 return $name;
1475 foreach (array_keys($this->validators) as $test) {
1476 if (preg_match('/' . preg_quote($name) . '$/i', $test)) {
1477 return $test;
1481 return false;
1485 * Retrieve internal identifier for a named filter
1487 * @param string $name
1488 * @return string
1490 protected function getFilterIdentifier($name)
1492 if (array_key_exists($name, $this->filters)) {
1493 return $name;
1496 foreach (array_keys($this->filters) as $test) {
1497 if (preg_match('/' . preg_quote($name) . '$/i', $test)) {
1498 return $test;
1502 return false;