3 * Zend Framework (http://framework.zend.com/)
5 * @link http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license http://framework.zend.com/license/new-bsd New BSD License
10 namespace Zend\File\Transfer\Adapter
;
14 use Zend\File\Transfer
;
15 use Zend\File\Transfer\Exception
;
17 use Zend\Filter\Exception
as FilterException
;
18 use Zend\I18n\Translator\TranslatorInterface
as Translator
;
19 use Zend\I18n\Translator\TranslatorAwareInterface
;
20 use Zend\ServiceManager\ServiceManager
;
21 use Zend\Stdlib\ErrorHandler
;
25 * Abstract class for file transfers (Downloads and Uploads)
27 * This class needs a full rewrite. It re-implements functionality present in
28 * Zend\Filter\Input and/or Zend\Form\Element, and in a way that's inconsistent
29 * with either one. Additionally, plugin loader usage is now deprecated -- but
30 * modifying that should be done in tandem with a rewrite to utilize validator
31 * and filter chains instead.
33 * @deprecated since 2.7.0, and scheduled for removal with 3.0.0
35 abstract class AbstractAdapter
implements TranslatorAwareInterface
38 * Plugin loader Constants
40 const FILTER
= 'FILTER';
41 const VALIDATOR
= 'VALIDATOR';
45 * Internal list of breaks
49 protected $break = [];
52 * @var FilterPluginManager
54 protected $filterManager;
57 * Internal list of filters
61 protected $filters = [];
64 * Plugin loaders for filter and validation chains
68 protected $loaders = [];
71 * Internal list of messages
75 protected $messages = [];
80 protected $translator;
83 * Is translation enabled?
87 protected $translatorEnabled = true;
90 * Translator text domain (optional)
94 protected $translatorTextDomain = 'default';
97 * @var ValidatorPluginManager
99 protected $validatorManager;
102 * Internal list of validators
105 protected $validators = [];
108 * Internal list of files
109 * This array looks like this:
110 * array(form => array( - Form is the name within the form or, if not set the filename
111 * name, - Original name of this file
112 * type, - Mime type of this file
113 * size, - Filesize in bytes
114 * tmp_name, - Internally temporary filename for uploaded files
115 * error, - Error which has occurred
116 * destination, - New destination for this file
117 * validators, - Set validator names for this file
118 * files - Set file names for this file
123 protected $files = [];
132 * Available options for file transfers
134 protected $options = [
135 'ignoreNoFile' => false,
136 'useByteString' => true,
138 'detectInfos' => true,
144 * @param mixed $options
147 abstract public function send($options = null);
152 * @param mixed $options
155 abstract public function receive($options = null);
160 * @param array|string|null $files
163 abstract public function isSent($files = null);
168 * @param array|string|null $files
171 abstract public function isReceived($files = null);
174 * Has a file been uploaded ?
176 * @param array|string|null $files
179 abstract public function isUploaded($files = null);
182 * Has the file been filtered ?
184 * @param array|string|null $files
187 abstract public function isFiltered($files = null);
190 * Adds one or more files
192 * @param string|array $file File to add
193 * @param string|array $validator Validators to use for this file, must be set before
194 * @param string|array $filter Filters to use for this file, must be set before
195 * @return AbstractAdapter
196 * @throws Exception Not implemented
198 //abstract public function addFile($file, $validator = null, $filter = null);
201 * Returns all set types
203 * @return array List of set types
204 * @throws Exception Not implemented
206 //abstract public function getType();
209 * Adds one or more type of files
211 * @param string|array $type Type of files to add
212 * @param string|array $validator Validators to use for this file, must be set before
213 * @param string|array $filter Filters to use for this file, must be set before
214 * @return AbstractAdapter
215 * @throws Exception Not implemented
217 //abstract public function addType($type, $validator = null, $filter = null);
220 * Returns all set files
222 * @return array List of set files
224 //abstract public function getFile();
227 * Set the filter plugin manager instance
229 * @param FilterPluginManager $filterManager
230 * @return AbstractAdapter
232 public function setFilterManager(FilterPluginManager
$filterManager)
234 $this->filterManager
= $filterManager;
239 * Get the filter plugin manager instance
241 * @return FilterPluginManager
243 public function getFilterManager()
245 if (! $this->filterManager
instanceof FilterPluginManager
) {
246 $this->setFilterManager(new FilterPluginManager(new ServiceManager()));
248 return $this->filterManager
;
252 * Set the validator plugin manager instance
254 * @param ValidatorPluginManager $validatorManager
255 * @return AbstractAdapter
257 public function setValidatorManager(ValidatorPluginManager
$validatorManager)
259 $this->validatorManager
= $validatorManager;
264 * Get the validator plugin manager instance
266 * @return ValidatorPluginManager
268 public function getValidatorManager()
270 if (! $this->validatorManager
instanceof ValidatorPluginManager
) {
271 if ($this->isServiceManagerV3()) {
272 $this->setValidatorManager(new ValidatorPluginManager(new ServiceManager()));
274 $this->setValidatorManager(new ValidatorPluginManager());
277 return $this->validatorManager
;
281 * Adds a new validator for this class
283 * @param string|Validator\ValidatorInterface $validator Type of validator to add
284 * @param bool $breakChainOnFailure If the validation chain should stop a failure
285 * @param string|array $options Options to set for the validator
286 * @param string|array $files Files to limit this validator to
287 * @return AbstractAdapter
288 * @throws Exception\InvalidArgumentException for invalid type
290 public function addValidator($validator, $breakChainOnFailure = false, $options = null, $files = null)
292 if (is_string($validator)) {
293 $options = (null !== $options && is_scalar($options)) ?
[$options] : $options;
294 $validator = $this->getValidatorManager()->get($validator, $options);
295 if (is_array($options) && isset($options['messages'])) {
296 if (is_array($options['messages'])) {
297 $validator->setMessages($options['messages']);
298 } elseif (is_string($options['messages'])) {
299 $validator->setMessage($options['messages']);
302 unset($options['messages']);
306 if (! $validator instanceof Validator\ValidatorInterface
) {
307 throw new Exception\
InvalidArgumentException(
308 'Invalid validator provided to addValidator; ' .
309 'must be string or Zend\Validator\ValidatorInterface'
313 $name = get_class($validator);
315 $this->validators
[$name] = $validator;
316 $this->break[$name] = $breakChainOnFailure;
317 $files = $this->getFiles($files, true, true);
318 foreach ($files as $file) {
319 if ($name == 'NotEmpty') {
320 $temp = $this->files
[$file]['validators'];
321 $this->files
[$file]['validators'] = [$name];
322 $this->files
[$file]['validators'] +
= $temp;
324 $this->files
[$file]['validators'][] = $name;
327 $this->files
[$file]['validated'] = false;
334 * Add Multiple validators at once
336 * @param array $validators
337 * @param string|array $files
338 * @return AbstractAdapter
339 * @throws Exception\InvalidArgumentException for invalid type
341 public function addValidators(array $validators, $files = null)
343 foreach ($validators as $name => $validatorInfo) {
344 if ($validatorInfo instanceof Validator\ValidatorInterface
) {
345 $this->addValidator($validatorInfo, null, null, $files);
346 } elseif (is_string($validatorInfo)) {
347 if (! is_int($name)) {
348 $this->addValidator($name, null, $validatorInfo, $files);
350 $this->addValidator($validatorInfo, null, null, $files);
352 } elseif (is_array($validatorInfo)) {
353 $argc = count($validatorInfo);
354 $breakChainOnFailure = false;
356 if (isset($validatorInfo['validator'])) {
357 $validator = $validatorInfo['validator'];
358 if (isset($validatorInfo['breakChainOnFailure'])) {
359 $breakChainOnFailure = $validatorInfo['breakChainOnFailure'];
362 if (isset($validatorInfo['options'])) {
363 $options = $validatorInfo['options'];
366 $this->addValidator($validator, $breakChainOnFailure, $options, $files);
368 if (is_string($name)) {
370 $options = $validatorInfo;
371 $this->addValidator($validator, $breakChainOnFailure, $options, $files);
378 $validator = array_shift($validatorInfo);
381 $breakChainOnFailure = array_shift($validatorInfo);
384 $options = array_shift($validatorInfo);
387 if (! empty($validatorInfo)) {
388 $file = array_shift($validatorInfo);
392 $this->addValidator($validator, $breakChainOnFailure, $options, $file);
398 throw new Exception\
InvalidArgumentException('Invalid validator passed to addValidators()');
406 * Sets a validator for the class, erasing all previous set
408 * @param array $validators Validators to set
409 * @param string|array $files Files to limit this validator to
410 * @return AbstractAdapter
412 public function setValidators(array $validators, $files = null)
414 $this->clearValidators();
415 return $this->addValidators($validators, $files);
419 * Determine if a given validator has already been registered
421 * @param string $name
424 public function hasValidator($name)
426 return (false !== $this->getValidatorIdentifier($name));
430 * Retrieve individual validator
432 * @param string $name
433 * @return Validator\ValidatorInterface|null
435 public function getValidator($name)
437 if (false === ($identifier = $this->getValidatorIdentifier($name))) {
440 return $this->validators
[$identifier];
444 * Returns all set validators
446 * @param string|array $files (Optional) Returns the validator for this files
447 * @return null|array List of set validators
449 public function getValidators($files = null)
451 if ($files === null) {
452 return $this->validators
;
455 $files = $this->getFiles($files, true, true);
457 foreach ($files as $file) {
458 if (! empty($this->files
[$file]['validators'])) {
459 $validators +
= $this->files
[$file]['validators'];
463 $validators = array_unique($validators);
465 foreach ($validators as $validator) {
466 $result[$validator] = $this->validators
[$validator];
473 * Remove an individual validator
475 * @param string $name
476 * @return AbstractAdapter
478 public function removeValidator($name)
480 if (false === ($key = $this->getValidatorIdentifier($name))) {
484 unset($this->validators
[$key]);
485 foreach (array_keys($this->files
) as $file) {
486 if (empty($this->files
[$file]['validators'])) {
490 $index = array_search($key, $this->files
[$file]['validators']);
491 if ($index === false) {
495 unset($this->files
[$file]['validators'][$index]);
496 $this->files
[$file]['validated'] = false;
503 * Remove all validators
505 * @return AbstractAdapter
507 public function clearValidators()
509 $this->validators
= [];
510 foreach (array_keys($this->files
) as $file) {
511 $this->files
[$file]['validators'] = [];
512 $this->files
[$file]['validated'] = false;
519 * Sets Options for adapters
521 * @param array $options Options to set
522 * @param array $files (Optional) Files to set the options for
523 * @return AbstractAdapter
525 public function setOptions($options = [], $files = null)
527 $file = $this->getFiles($files, false, true);
529 if (is_array($options)) {
531 $this->options
= array_merge($this->options
, $options);
534 foreach ($options as $name => $value) {
535 foreach ($file as $key => $content) {
538 $this->files
[$key]['options'][$name] = (string) $value;
542 case 'useByteString':
544 $this->files
[$key]['options'][$name] = (bool) $value;
558 * Returns set options for adapters or files
560 * @param array $files (Optional) Files to return the options for
561 * @return array Options for given files
563 public function getOptions($files = null)
565 $file = $this->getFiles($files, false, true);
567 foreach ($file as $key => $content) {
568 if (isset($this->files
[$key]['options'])) {
569 $options[$key] = $this->files
[$key]['options'];
579 * Checks if the files are valid
581 * @param string|array $files (Optional) Files to check
582 * @return bool True if all checks are valid
584 public function isValid($files = null)
586 $check = $this->getFiles($files, false, true);
591 $translator = $this->getTranslator();
592 $this->messages
= [];
594 foreach ($check as $content) {
595 if (array_key_exists('validators', $content) &&
596 in_array(Validator\File\Count
::class, $content['validators'])) {
597 $validator = $this->validators
[Validator\File\Count
::class];
599 if (empty($content['tmp_name'])) {
603 if (array_key_exists('destination', $content)) {
604 $checkit = $content['destination'];
606 $checkit = dirname($content['tmp_name']);
609 $checkit .= DIRECTORY_SEPARATOR
. $content['name'];
610 $validator->addFile($checkit);
615 if (! $validator->isValid($count['tmp_name'], $count)) {
616 $this->messages +
= $validator->getMessages();
620 foreach ($check as $key => $content) {
622 if (array_key_exists('validators', $content) && $content['validated']) {
626 if (array_key_exists('validators', $content)) {
627 foreach ($content['validators'] as $class) {
628 $validator = $this->validators
[$class];
629 if (method_exists($validator, 'setTranslator')) {
630 $validator->setTranslator($translator);
633 if (($class === 'Zend\Validator\File\Upload') && (empty($content['tmp_name']))) {
636 $tocheck = $content['tmp_name'];
639 if (! $validator->isValid($tocheck, $content)) {
640 $fileerrors +
= $validator->getMessages();
643 if (! empty($content['options']['ignoreNoFile']) && (isset($fileerrors['fileUploadErrorNoFile']))) {
644 unset($fileerrors['fileUploadErrorNoFile']);
648 if (($class === 'Zend\Validator\File\Upload') && (count($fileerrors) > 0)) {
652 if (($this->break[$class]) && (count($fileerrors) > 0)) {
659 if (count($fileerrors) > 0) {
660 $this->files
[$key]['validated'] = false;
662 $this->files
[$key]['validated'] = true;
665 $this->messages +
= $fileerrors;
671 if (count($this->messages
) > 0) {
679 * Returns found validation messages
683 public function getMessages()
685 return $this->messages
;
689 * Retrieve error codes
693 public function getErrors()
695 return array_keys($this->messages
);
699 * Are there errors registered?
703 public function hasErrors()
705 return (! empty($this->messages
));
709 * Adds a new filter for this class
711 * @param string|Filter\FilterInterface $filter Type of filter to add
712 * @param string|array $options Options to set for the filter
713 * @param string|array $files Files to limit this filter to
714 * @return AbstractAdapter
715 * @throws Exception\InvalidArgumentException for invalid type
717 public function addFilter($filter, $options = null, $files = null)
719 if (is_string($filter)) {
720 $options = (null !== $options && is_scalar($options)) ?
[$options] : $options;
721 $filter = $this->getFilterManager()->get($filter, $options);
724 if (! $filter instanceof Filter\FilterInterface
) {
725 throw new Exception\
InvalidArgumentException('Invalid filter specified');
728 $class = get_class($filter);
729 $this->filters
[$class] = $filter;
730 $files = $this->getFiles($files, true, true);
731 foreach ($files as $file) {
732 $this->files
[$file]['filters'][] = $class;
739 * Add Multiple filters at once
741 * @param array $filters
742 * @param string|array $files
743 * @return AbstractAdapter
745 public function addFilters(array $filters, $files = null)
747 foreach ($filters as $key => $spec) {
748 if ($spec instanceof Filter\FilterInterface
) {
749 $this->addFilter($spec, null, $files);
753 if (is_string($key)) {
754 $this->addFilter($key, $spec, $files);
759 if (is_string($spec)) {
760 $this->addFilter($spec, null, $files);
764 if (is_array($spec)) {
765 if (! array_key_exists('filter', $spec)) {
769 $filter = $spec['filter'];
770 unset($spec['filter']);
771 $this->addFilter($filter, $spec, $files);
783 * Sets a filter for the class, erasing all previous set
785 * @param array $filters Filter to set
786 * @param string|array $files Files to limit this filter to
787 * @return Filter\AbstractFilter
789 public function setFilters(array $filters, $files = null)
791 $this->clearFilters();
792 return $this->addFilters($filters, $files);
796 * Determine if a given filter has already been registered
798 * @param string $name
801 public function hasFilter($name)
803 return (false !== $this->getFilterIdentifier($name));
807 * Retrieve individual filter
809 * @param string $name
810 * @return Filter\FilterInterface|null
812 public function getFilter($name)
814 if (false === ($identifier = $this->getFilterIdentifier($name))) {
818 return $this->filters
[$identifier];
822 * Returns all set filters
824 * @param string|array $files (Optional) Returns the filter for this files
825 * @return array List of set filters
826 * @throws Exception\RuntimeException When file not found
828 public function getFilters($files = null)
830 if ($files === null) {
831 return $this->filters
;
834 $files = $this->getFiles($files, true, true);
836 foreach ($files as $file) {
837 if (! empty($this->files
[$file]['filters'])) {
838 $filters +
= $this->files
[$file]['filters'];
842 $filters = array_unique($filters);
844 foreach ($filters as $filter) {
845 $result[] = $this->filters
[$filter];
852 * Remove an individual filter
854 * @param string $name
855 * @return AbstractAdapter
857 public function removeFilter($name)
859 if (false === ($key = $this->getFilterIdentifier($name))) {
863 unset($this->filters
[$key]);
864 foreach (array_keys($this->files
) as $file) {
865 if (empty($this->files
[$file]['filters'])) {
869 $index = array_search($key, $this->files
[$file]['filters']);
870 if ($index === false) {
874 unset($this->files
[$file]['filters'][$index]);
882 * @return AbstractAdapter
884 public function clearFilters()
887 foreach (array_keys($this->files
) as $file) {
888 $this->files
[$file]['filters'] = [];
895 * Retrieves the filename of transferred files.
897 * @param string $file (Optional) Element to return the filename for
898 * @param bool $path (Optional) Should the path also be returned ?
899 * @return string|array
901 public function getFileName($file = null, $path = true)
903 $files = $this->getFiles($file, true, true);
906 foreach ($files as $file) {
907 if (empty($this->files
[$file]['name'])) {
911 if ($path === true) {
912 $directory = $this->getDestination($file) . DIRECTORY_SEPARATOR
;
915 $result[$file] = $directory . $this->files
[$file]['name'];
918 if (count($result) == 1) {
919 return current($result);
926 * Retrieve additional internal file information for files
928 * @param string $file (Optional) File to get information for
931 public function getFileInfo($file = null)
933 return $this->getFiles($file);
937 * Sets a new destination for the given files
939 * @deprecated Will be changed to be a filter!!!
940 * @param string $destination New destination directory
941 * @param string|array $files Files to set the new destination for
942 * @return AbstractAdapter
943 * @throws Exception\InvalidArgumentException when the given destination is not a directory or does not exist
945 public function setDestination($destination, $files = null)
948 $destination = rtrim($destination, "/\\");
949 if (! is_dir($destination)) {
950 throw new Exception\
InvalidArgumentException('The given destination is not a directory or does not exist');
953 if (! is_writable($destination)) {
954 throw new Exception\
InvalidArgumentException('The given destination is not writeable');
957 if ($files === null) {
958 foreach ($this->files
as $file => $content) {
959 $this->files
[$file]['destination'] = $destination;
962 $files = $this->getFiles($files, true, true);
963 if (empty($files) and is_string($orig)) {
964 $this->files
[$orig]['destination'] = $destination;
967 foreach ($files as $file) {
968 $this->files
[$file]['destination'] = $destination;
976 * Retrieve destination directory value
978 * @param null|string|array $files
979 * @throws Exception\InvalidArgumentException
980 * @return null|string|array
982 public function getDestination($files = null)
985 $files = $this->getFiles($files, false, true);
987 if (empty($files) and is_string($orig)) {
988 if (isset($this->files
[$orig]['destination'])) {
989 $destinations[$orig] = $this->files
[$orig]['destination'];
991 throw new Exception\
InvalidArgumentException(
992 sprintf('The file transfer adapter can not find "%s"', $orig)
997 foreach ($files as $key => $content) {
998 if (isset($this->files
[$key]['destination'])) {
999 $destinations[$key] = $this->files
[$key]['destination'];
1001 $tmpdir = $this->getTmpDir();
1002 $this->setDestination($tmpdir, $key);
1003 $destinations[$key] = $tmpdir;
1007 if (empty($destinations)) {
1008 $destinations = $this->getTmpDir();
1009 } elseif (count($destinations) == 1) {
1010 $destinations = current($destinations);
1013 return $destinations;
1017 * Sets translator to use in helper
1019 * @param Translator $translator [optional] translator.
1020 * Default is null, which sets no translator.
1021 * @param string $textDomain [optional] text domain
1022 * Default is null, which skips setTranslatorTextDomain
1023 * @return AbstractAdapter
1025 public function setTranslator(Translator
$translator = null, $textDomain = null)
1027 $this->translator
= $translator;
1028 if (null !== $textDomain) {
1029 $this->setTranslatorTextDomain($textDomain);
1035 * Retrieve localization translator object
1037 * @return Translator|null
1039 public function getTranslator()
1041 if ($this->isTranslatorEnabled()) {
1045 return $this->translator
;
1049 * Checks if the helper has a translator
1053 public function hasTranslator()
1055 return (bool) $this->getTranslator();
1059 * Indicate whether or not translation should be enabled
1062 * @return AbstractAdapter
1064 public function setTranslatorEnabled($flag = true)
1066 $this->translatorEnabled
= (bool) $flag;
1071 * Is translation enabled?
1075 public function isTranslatorEnabled()
1077 return $this->translatorEnabled
;
1081 * Set translation text domain
1083 * @param string $textDomain
1084 * @return AbstractAdapter
1086 public function setTranslatorTextDomain($textDomain = 'default')
1088 $this->translatorTextDomain
= $textDomain;
1093 * Return the translation text domain
1097 public function getTranslatorTextDomain()
1099 return $this->translatorTextDomain
;
1103 * Returns the hash for a given file
1105 * @param string $hash Hash algorithm to use
1106 * @param string|array $files Files to return the hash for
1107 * @return string|array Hashstring
1108 * @throws Exception\InvalidArgumentException On unknown hash algorithm
1110 public function getHash($hash = 'crc32', $files = null)
1112 if (! in_array($hash, hash_algos())) {
1113 throw new Exception\
InvalidArgumentException('Unknown hash algorithm');
1116 $files = $this->getFiles($files);
1118 foreach ($files as $key => $value) {
1119 if (file_exists($value['name'])) {
1120 $result[$key] = hash_file($hash, $value['name']);
1121 } elseif (file_exists($value['tmp_name'])) {
1122 $result[$key] = hash_file($hash, $value['tmp_name']);
1123 } elseif (empty($value['options']['ignoreNoFile'])) {
1124 throw new Exception\
InvalidArgumentException("The file '{$value['name']}' does not exist");
1128 if (count($result) == 1) {
1129 return current($result);
1136 * Returns the real filesize of the file
1138 * @param string|array $files Files to get the filesize from
1139 * @return string|array Filesize
1140 * @throws Exception\InvalidArgumentException When the file does not exist
1142 public function getFileSize($files = null)
1144 $files = $this->getFiles($files);
1146 foreach ($files as $key => $value) {
1147 if (file_exists($value['name']) ||
file_exists($value['tmp_name'])) {
1148 if ($value['options']['useByteString']) {
1149 $result[$key] = static::toByteString($value['size']);
1151 $result[$key] = $value['size'];
1153 } elseif (empty($value['options']['ignoreNoFile'])) {
1154 throw new Exception\
InvalidArgumentException("The file '{$value['name']}' does not exist");
1160 if (count($result) == 1) {
1161 return current($result);
1168 * Internal method to detect the size of a file
1170 * @param array $value File infos
1171 * @return string Filesize of given file
1173 protected function detectFileSize($value)
1175 if (file_exists($value['name'])) {
1176 $filename = $value['name'];
1177 } elseif (file_exists($value['tmp_name'])) {
1178 $filename = $value['tmp_name'];
1183 ErrorHandler
::start();
1184 $filesize = filesize($filename);
1185 $return = ErrorHandler
::stop();
1186 if ($return instanceof ErrorException
) {
1190 return sprintf("%u", $filesize);
1194 * Returns the real mimetype of the file
1195 * Uses fileinfo, when not available mime_magic and as last fallback a manual given mimetype
1197 * @param string|array $files Files to get the mimetype from
1198 * @return string|array MimeType
1199 * @throws Exception\InvalidArgumentException When the file does not exist
1201 public function getMimeType($files = null)
1203 $files = $this->getFiles($files);
1205 foreach ($files as $key => $value) {
1206 if (file_exists($value['name']) ||
file_exists($value['tmp_name'])) {
1207 $result[$key] = $value['type'];
1208 } elseif (empty($value['options']['ignoreNoFile'])) {
1209 throw new Exception\
InvalidArgumentException("the file '{$value['name']}' does not exist");
1215 if (count($result) == 1) {
1216 return current($result);
1223 * Internal method to detect the mime type of a file
1225 * @param array $value File infos
1226 * @return string Mimetype of given file
1228 protected function detectMimeType($value)
1230 if (file_exists($value['name'])) {
1231 $file = $value['name'];
1232 } elseif (file_exists($value['tmp_name'])) {
1233 $file = $value['tmp_name'];
1238 if (class_exists('finfo', false)) {
1239 if (! empty($value['options']['magicFile'])) {
1240 ErrorHandler
::start();
1241 $mime = finfo_open(FILEINFO_MIME_TYPE
, $value['options']['magicFile']);
1242 ErrorHandler
::stop();
1246 ErrorHandler
::start();
1247 $mime = finfo_open(FILEINFO_MIME_TYPE
);
1248 ErrorHandler
::stop();
1251 if (! empty($mime)) {
1252 $result = finfo_file($mime, $file);
1258 if (empty($result) && (function_exists('mime_content_type')
1259 && ini_get('mime_magic.magicfile'))) {
1260 $result = mime_content_type($file);
1263 if (empty($result)) {
1264 $result = 'application/octet-stream';
1271 * Returns the formatted size
1276 protected static function toByteString($size)
1278 $sizes = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
1279 for ($i = 0; $size >= 1024 && $i < 9; $i++
) {
1283 return round($size, 2) . $sizes[$i];
1287 * Internal function to filter all given files
1289 * @param string|array $files (Optional) Files to check
1290 * @return bool False on error
1292 protected function filter($files = null)
1294 $check = $this->getFiles($files);
1295 foreach ($check as $name => $content) {
1296 if (array_key_exists('filters', $content)) {
1297 foreach ($content['filters'] as $class) {
1298 $filter = $this->filters
[$class];
1300 $result = $filter->filter($this->getFileName($name));
1302 $this->files
[$name]['destination'] = dirname($result);
1303 $this->files
[$name]['name'] = basename($result);
1304 } catch (FilterException\ExceptionInterface
$e) {
1305 $this->messages +
= [$e->getMessage()];
1311 if (count($this->messages
) > 0) {
1319 * Determine system TMP directory and detect if we have read access
1322 * @throws Exception\RuntimeException if unable to determine directory
1324 protected function getTmpDir()
1326 if (null === $this->tmpDir
) {
1328 if (function_exists('sys_get_temp_dir')) {
1329 $tmpdir[] = sys_get_temp_dir();
1332 if (! empty($_ENV['TMP'])) {
1333 $tmpdir[] = realpath($_ENV['TMP']);
1336 if (! empty($_ENV['TMPDIR'])) {
1337 $tmpdir[] = realpath($_ENV['TMPDIR']);
1340 if (! empty($_ENV['TEMP'])) {
1341 $tmpdir[] = realpath($_ENV['TEMP']);
1344 $upload = ini_get('upload_tmp_dir');
1346 $tmpdir[] = realpath($upload);
1349 foreach ($tmpdir as $directory) {
1350 if ($this->isPathWriteable($directory)) {
1351 $this->tmpDir
= $directory;
1355 if (empty($this->tmpDir
)) {
1356 // Attemp to detect by creating a temporary file
1357 $tempFile = tempnam(md5(uniqid(rand(), true)), '');
1359 $this->tmpDir
= realpath(dirname($tempFile));
1362 throw new Exception\
RuntimeException('Could not determine a temporary directory');
1366 $this->tmpDir
= rtrim($this->tmpDir
, "/\\");
1368 return $this->tmpDir
;
1372 * Tries to detect if we can read and write to the given path
1374 * @param string $path
1377 protected function isPathWriteable($path)
1379 $tempFile = rtrim($path, "/\\");
1380 $tempFile .= '/' . 'test.1';
1382 ErrorHandler
::start();
1383 $result = file_put_contents($tempFile, 'TEST');
1384 ErrorHandler
::stop();
1386 if ($result == false) {
1390 ErrorHandler
::start();
1391 $result = unlink($tempFile);
1392 ErrorHandler
::stop();
1394 if ($result == false) {
1402 * Returns found files based on internal file array and given files
1404 * @param string|array $files (Optional) Files to return
1405 * @param bool $names (Optional) Returns only names on true, else complete info
1406 * @param bool $noexception (Optional) Allows throwing an exception, otherwise returns an empty array
1407 * @return array Found files
1408 * @throws Exception\RuntimeException On false filename
1410 protected function getFiles($files, $names = false, $noexception = false)
1414 if (is_string($files)) {
1418 if (is_array($files)) {
1419 foreach ($files as $find) {
1421 foreach ($this->files
as $file => $content) {
1422 if (! isset($content['name'])) {
1426 if (($content['name'] === $find) && isset($content['multifiles'])) {
1427 foreach ($content['multifiles'] as $multifile) {
1428 $found[] = $multifile;
1433 if ($file === $find) {
1438 if ($content['name'] === $find) {
1444 if (empty($found)) {
1445 if ($noexception !== false) {
1449 throw new Exception\
RuntimeException(sprintf('The file transfer adapter can not find "%s"', $find));
1452 foreach ($found as $checked) {
1453 $check[$checked] = $this->files
[$checked];
1458 if ($files === null) {
1459 $check = $this->files
;
1460 $keys = array_keys($check);
1461 foreach ($keys as $key) {
1462 if (isset($check[$key]['multifiles'])) {
1463 unset($check[$key]);
1469 $check = array_keys($check);
1476 * Retrieve internal identifier for a named validator
1478 * @param string $name
1481 protected function getValidatorIdentifier($name)
1483 if (array_key_exists($name, $this->validators
)) {
1487 foreach (array_keys($this->validators
) as $test) {
1488 if (preg_match('/' . preg_quote($name) . '$/i', $test)) {
1497 * Retrieve internal identifier for a named filter
1499 * @param string $name
1502 protected function getFilterIdentifier($name)
1504 if (array_key_exists($name, $this->filters
)) {
1508 foreach (array_keys($this->filters
) as $test) {
1509 if (preg_match('/' . preg_quote($name) . '$/i', $test)) {
1518 * Is the service manager component v3?
1520 * This is needed until zend-validator is updated, to ensure we instantiate
1521 * the validator plugin manager properly.
1525 private function isServiceManagerV3()
1527 $r = new ReflectionClass(ServiceManager
::class);
1528 return ! $r->hasProperty('invokableClasses');