File indexing completed on 2024-12-29 05:27:38
0001 <?php 0002 /** 0003 * Zend Framework 0004 * 0005 * LICENSE 0006 * 0007 * This source file is subject to the new BSD license that is bundled 0008 * with this package in the file LICENSE.txt. 0009 * It is also available through the world-wide-web at this URL: 0010 * http://framework.zend.com/license/new-bsd 0011 * If you did not receive a copy of the license and are unable to 0012 * obtain it through the world-wide-web, please send an email 0013 * to license@zend.com so we can send you a copy immediately. 0014 * 0015 * @category Zend 0016 * @package Zend_File_Transfer 0017 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0018 * @license http://framework.zend.com/license/new-bsd New BSD License 0019 * @version $Id$ 0020 */ 0021 0022 /** 0023 * Abstract class for file transfers (Downloads and Uploads) 0024 * 0025 * @category Zend 0026 * @package Zend_File_Transfer 0027 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com) 0028 * @license http://framework.zend.com/license/new-bsd New BSD License 0029 */ 0030 abstract class Zend_File_Transfer_Adapter_Abstract 0031 { 0032 /**@+ 0033 * Plugin loader Constants 0034 */ 0035 const FILTER = 'FILTER'; 0036 const VALIDATE = 'VALIDATE'; 0037 /**@-*/ 0038 0039 /** 0040 * Internal list of breaks 0041 * 0042 * @var array 0043 */ 0044 protected $_break = array(); 0045 0046 /** 0047 * Internal list of filters 0048 * 0049 * @var array 0050 */ 0051 protected $_filters = array(); 0052 0053 /** 0054 * Plugin loaders for filter and validation chains 0055 * 0056 * @var array 0057 */ 0058 protected $_loaders = array(); 0059 0060 /** 0061 * Internal list of messages 0062 * 0063 * @var array 0064 */ 0065 protected $_messages = array(); 0066 0067 /** 0068 * @var Zend_Translate 0069 */ 0070 protected $_translator; 0071 0072 /** 0073 * Is translation disabled? 0074 * 0075 * @var bool 0076 */ 0077 protected $_translatorDisabled = false; 0078 0079 /** 0080 * Internal list of validators 0081 * @var array 0082 */ 0083 protected $_validators = array(); 0084 0085 /** 0086 * Internal list of files 0087 * This array looks like this: 0088 * array(form => array( - Form is the name within the form or, if not set the filename 0089 * name, - Original name of this file 0090 * type, - Mime type of this file 0091 * size, - Filesize in bytes 0092 * tmp_name, - Internalally temporary filename for uploaded files 0093 * error, - Error which has occured 0094 * destination, - New destination for this file 0095 * validators, - Set validator names for this file 0096 * files - Set file names for this file 0097 * )) 0098 * 0099 * @var array 0100 */ 0101 protected $_files = array(); 0102 0103 /** 0104 * TMP directory 0105 * @var string 0106 */ 0107 protected $_tmpDir; 0108 0109 /** 0110 * Available options for file transfers 0111 */ 0112 protected $_options = array( 0113 'ignoreNoFile' => false, 0114 'useByteString' => true, 0115 'magicFile' => null, 0116 'detectInfos' => true, 0117 ); 0118 0119 /** 0120 * Send file 0121 * 0122 * @param mixed $options 0123 * @return bool 0124 */ 0125 abstract public function send($options = null); 0126 0127 /** 0128 * Receive file 0129 * 0130 * @param mixed $options 0131 * @return bool 0132 */ 0133 abstract public function receive($options = null); 0134 0135 /** 0136 * Is file sent? 0137 * 0138 * @param array|string|null $files 0139 * @return bool 0140 */ 0141 abstract public function isSent($files = null); 0142 0143 /** 0144 * Is file received? 0145 * 0146 * @param array|string|null $files 0147 * @return bool 0148 */ 0149 abstract public function isReceived($files = null); 0150 0151 /** 0152 * Has a file been uploaded ? 0153 * 0154 * @param array|string|null $files 0155 * @return bool 0156 */ 0157 abstract public function isUploaded($files = null); 0158 0159 /** 0160 * Has the file been filtered ? 0161 * 0162 * @param array|string|null $files 0163 * @return bool 0164 */ 0165 abstract public function isFiltered($files = null); 0166 0167 /** 0168 * Retrieve progress of transfer 0169 * 0170 * @return float 0171 */ 0172 public static function getProgress() 0173 { 0174 // require_once 'Zend/File/Transfer/Exception.php'; 0175 throw new Zend_File_Transfer_Exception('Method must be implemented within the adapter'); 0176 } 0177 0178 /** 0179 * Set plugin loader to use for validator or filter chain 0180 * 0181 * @param Zend_Loader_PluginLoader_Interface $loader 0182 * @param string $type 'filter', or 'validate' 0183 * @return Zend_File_Transfer_Adapter_Abstract 0184 * @throws Zend_File_Transfer_Exception on invalid type 0185 */ 0186 public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type) 0187 { 0188 $type = strtoupper($type); 0189 switch ($type) { 0190 case self::FILTER: 0191 case self::VALIDATE: 0192 $this->_loaders[$type] = $loader; 0193 return $this; 0194 default: 0195 // require_once 'Zend/File/Transfer/Exception.php'; 0196 throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type)); 0197 } 0198 } 0199 0200 /** 0201 * Retrieve plugin loader for validator or filter chain 0202 * 0203 * Instantiates with default rules if none available for that type. Use 0204 * 'filter' or 'validate' for $type. 0205 * 0206 * @param string $type 0207 * @return Zend_Loader_PluginLoader 0208 * @throws Zend_File_Transfer_Exception on invalid type. 0209 */ 0210 public function getPluginLoader($type) 0211 { 0212 $type = strtoupper($type); 0213 switch ($type) { 0214 case self::FILTER: 0215 case self::VALIDATE: 0216 $prefixSegment = ucfirst(strtolower($type)); 0217 $pathSegment = $prefixSegment; 0218 if (!isset($this->_loaders[$type])) { 0219 $paths = array( 0220 'Zend_' . $prefixSegment . '_' => 'Zend/' . $pathSegment . '/', 0221 'Zend_' . $prefixSegment . '_File' => 'Zend/' . $pathSegment . '/File', 0222 ); 0223 0224 // require_once 'Zend/Loader/PluginLoader.php'; 0225 $this->_loaders[$type] = new Zend_Loader_PluginLoader($paths); 0226 } else { 0227 $loader = $this->_loaders[$type]; 0228 $prefix = 'Zend_' . $prefixSegment . '_File_'; 0229 if (!$loader->getPaths($prefix)) { 0230 $loader->addPrefixPath($prefix, str_replace('_', '/', $prefix)); 0231 } 0232 } 0233 return $this->_loaders[$type]; 0234 default: 0235 // require_once 'Zend/File/Transfer/Exception.php'; 0236 throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); 0237 } 0238 } 0239 0240 /** 0241 * Add prefix path for plugin loader 0242 * 0243 * If no $type specified, assumes it is a base path for both filters and 0244 * validators, and sets each according to the following rules: 0245 * - filters: $prefix = $prefix . '_Filter' 0246 * - validators: $prefix = $prefix . '_Validate' 0247 * 0248 * Otherwise, the path prefix is set on the appropriate plugin loader. 0249 * 0250 * @param string $prefix 0251 * @param string $path 0252 * @param string $type 0253 * @return Zend_File_Transfer_Adapter_Abstract 0254 * @throws Zend_File_Transfer_Exception for invalid type 0255 */ 0256 public function addPrefixPath($prefix, $path, $type = null) 0257 { 0258 $type = strtoupper($type); 0259 switch ($type) { 0260 case self::FILTER: 0261 case self::VALIDATE: 0262 $loader = $this->getPluginLoader($type); 0263 $loader->addPrefixPath($prefix, $path); 0264 return $this; 0265 case null: 0266 $prefix = rtrim($prefix, '_'); 0267 $path = rtrim($path, DIRECTORY_SEPARATOR); 0268 foreach (array(self::FILTER, self::VALIDATE) as $type) { 0269 $cType = ucfirst(strtolower($type)); 0270 $pluginPath = $path . DIRECTORY_SEPARATOR . $cType . DIRECTORY_SEPARATOR; 0271 $pluginPrefix = $prefix . '_' . $cType; 0272 $loader = $this->getPluginLoader($type); 0273 $loader->addPrefixPath($pluginPrefix, $pluginPath); 0274 } 0275 return $this; 0276 default: 0277 // require_once 'Zend/File/Transfer/Exception.php'; 0278 throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type)); 0279 } 0280 } 0281 0282 /** 0283 * Add many prefix paths at once 0284 * 0285 * @param array $spec 0286 * @return Zend_File_Transfer_Exception 0287 */ 0288 public function addPrefixPaths(array $spec) 0289 { 0290 if (isset($spec['prefix']) && isset($spec['path'])) { 0291 return $this->addPrefixPath($spec['prefix'], $spec['path']); 0292 } 0293 foreach ($spec as $type => $paths) { 0294 if (is_numeric($type) && is_array($paths)) { 0295 $type = null; 0296 if (isset($paths['prefix']) && isset($paths['path'])) { 0297 if (isset($paths['type'])) { 0298 $type = $paths['type']; 0299 } 0300 $this->addPrefixPath($paths['prefix'], $paths['path'], $type); 0301 } 0302 } elseif (!is_numeric($type)) { 0303 if (!isset($paths['prefix']) || !isset($paths['path'])) { 0304 foreach ($paths as $prefix => $spec) { 0305 if (is_array($spec)) { 0306 foreach ($spec as $path) { 0307 if (!is_string($path)) { 0308 continue; 0309 } 0310 $this->addPrefixPath($prefix, $path, $type); 0311 } 0312 } elseif (is_string($spec)) { 0313 $this->addPrefixPath($prefix, $spec, $type); 0314 } 0315 } 0316 } else { 0317 $this->addPrefixPath($paths['prefix'], $paths['path'], $type); 0318 } 0319 } 0320 } 0321 return $this; 0322 } 0323 0324 /** 0325 * Adds a new validator for this class 0326 * 0327 * @param string|array $validator Type of validator to add 0328 * @param boolean $breakChainOnFailure If the validation chain should stop an failure 0329 * @param string|array $options Options to set for the validator 0330 * @param string|array $files Files to limit this validator to 0331 * @return Zend_File_Transfer_Adapter 0332 */ 0333 public function addValidator($validator, $breakChainOnFailure = false, $options = null, $files = null) 0334 { 0335 if ($validator instanceof Zend_Validate_Interface) { 0336 $name = get_class($validator); 0337 } elseif (is_string($validator)) { 0338 $name = $this->getPluginLoader(self::VALIDATE)->load($validator); 0339 $validator = new $name($options); 0340 if (is_array($options) && isset($options['messages'])) { 0341 if (is_array($options['messages'])) { 0342 $validator->setMessages($options['messages']); 0343 } elseif (is_string($options['messages'])) { 0344 $validator->setMessage($options['messages']); 0345 } 0346 0347 unset($options['messages']); 0348 } 0349 } else { 0350 // require_once 'Zend/File/Transfer/Exception.php'; 0351 throw new Zend_File_Transfer_Exception('Invalid validator provided to addValidator; must be string or Zend_Validate_Interface'); 0352 } 0353 0354 $this->_validators[$name] = $validator; 0355 $this->_break[$name] = $breakChainOnFailure; 0356 $files = $this->_getFiles($files, true, true); 0357 foreach ($files as $file) { 0358 if ($name == 'NotEmpty') { 0359 $temp = $this->_files[$file]['validators']; 0360 $this->_files[$file]['validators'] = array($name); 0361 $this->_files[$file]['validators'] += $temp; 0362 } else { 0363 $this->_files[$file]['validators'][] = $name; 0364 } 0365 0366 $this->_files[$file]['validated'] = false; 0367 } 0368 0369 return $this; 0370 } 0371 0372 /** 0373 * Add Multiple validators at once 0374 * 0375 * @param array $validators 0376 * @param string|array $files 0377 * @return Zend_File_Transfer_Adapter_Abstract 0378 */ 0379 public function addValidators(array $validators, $files = null) 0380 { 0381 foreach ($validators as $name => $validatorInfo) { 0382 if ($validatorInfo instanceof Zend_Validate_Interface) { 0383 $this->addValidator($validatorInfo, null, null, $files); 0384 } else if (is_string($validatorInfo)) { 0385 if (!is_int($name)) { 0386 $this->addValidator($name, null, $validatorInfo, $files); 0387 } else { 0388 $this->addValidator($validatorInfo, null, null, $files); 0389 } 0390 } else if (is_array($validatorInfo)) { 0391 $argc = count($validatorInfo); 0392 $breakChainOnFailure = false; 0393 $options = array(); 0394 if (isset($validatorInfo['validator'])) { 0395 $validator = $validatorInfo['validator']; 0396 if (isset($validatorInfo['breakChainOnFailure'])) { 0397 $breakChainOnFailure = $validatorInfo['breakChainOnFailure']; 0398 } 0399 0400 if (isset($validatorInfo['options'])) { 0401 $options = $validatorInfo['options']; 0402 } 0403 0404 $this->addValidator($validator, $breakChainOnFailure, $options, $files); 0405 } else { 0406 if (is_string($name)) { 0407 $validator = $name; 0408 $options = $validatorInfo; 0409 $this->addValidator($validator, $breakChainOnFailure, $options, $files); 0410 } else { 0411 $file = $files; 0412 switch (true) { 0413 case (0 == $argc): 0414 break; 0415 case (1 <= $argc): 0416 $validator = array_shift($validatorInfo); 0417 case (2 <= $argc): 0418 $breakChainOnFailure = array_shift($validatorInfo); 0419 case (3 <= $argc): 0420 $options = array_shift($validatorInfo); 0421 case (4 <= $argc): 0422 if (!empty($validatorInfo)) { 0423 $file = array_shift($validatorInfo); 0424 } 0425 default: 0426 $this->addValidator($validator, $breakChainOnFailure, $options, $file); 0427 break; 0428 } 0429 } 0430 } 0431 } else { 0432 // require_once 'Zend/File/Transfer/Exception.php'; 0433 throw new Zend_File_Transfer_Exception('Invalid validator passed to addValidators()'); 0434 } 0435 } 0436 0437 return $this; 0438 } 0439 0440 /** 0441 * Sets a validator for the class, erasing all previous set 0442 * 0443 * @param string|array $validator Validator to set 0444 * @param string|array $files Files to limit this validator to 0445 * @return Zend_File_Transfer_Adapter 0446 */ 0447 public function setValidators(array $validators, $files = null) 0448 { 0449 $this->clearValidators(); 0450 return $this->addValidators($validators, $files); 0451 } 0452 0453 /** 0454 * Determine if a given validator has already been registered 0455 * 0456 * @param string $name 0457 * @return bool 0458 */ 0459 public function hasValidator($name) 0460 { 0461 return (false !== $this->_getValidatorIdentifier($name)); 0462 } 0463 0464 /** 0465 * Retrieve individual validator 0466 * 0467 * @param string $name 0468 * @return Zend_Validate_Interface|null 0469 */ 0470 public function getValidator($name) 0471 { 0472 if (false === ($identifier = $this->_getValidatorIdentifier($name))) { 0473 return null; 0474 } 0475 return $this->_validators[$identifier]; 0476 } 0477 0478 /** 0479 * Returns all set validators 0480 * 0481 * @param string|array $files (Optional) Returns the validator for this files 0482 * @return null|array List of set validators 0483 */ 0484 public function getValidators($files = null) 0485 { 0486 if ($files == null) { 0487 return $this->_validators; 0488 } 0489 0490 $files = $this->_getFiles($files, true, true); 0491 $validators = array(); 0492 foreach ($files as $file) { 0493 if (!empty($this->_files[$file]['validators'])) { 0494 $validators += $this->_files[$file]['validators']; 0495 } 0496 } 0497 0498 $validators = array_unique($validators); 0499 $result = array(); 0500 foreach ($validators as $validator) { 0501 $result[$validator] = $this->_validators[$validator]; 0502 } 0503 0504 return $result; 0505 } 0506 0507 /** 0508 * Remove an individual validator 0509 * 0510 * @param string $name 0511 * @return Zend_File_Transfer_Adapter_Abstract 0512 */ 0513 public function removeValidator($name) 0514 { 0515 if (false === ($key = $this->_getValidatorIdentifier($name))) { 0516 return $this; 0517 } 0518 0519 unset($this->_validators[$key]); 0520 foreach (array_keys($this->_files) as $file) { 0521 if (empty($this->_files[$file]['validators'])) { 0522 continue; 0523 } 0524 0525 $index = array_search($key, $this->_files[$file]['validators']); 0526 if ($index === false) { 0527 continue; 0528 } 0529 0530 unset($this->_files[$file]['validators'][$index]); 0531 $this->_files[$file]['validated'] = false; 0532 } 0533 0534 return $this; 0535 } 0536 0537 /** 0538 * Remove all validators 0539 * 0540 * @return Zend_File_Transfer_Adapter_Abstract 0541 */ 0542 public function clearValidators() 0543 { 0544 $this->_validators = array(); 0545 foreach (array_keys($this->_files) as $file) { 0546 $this->_files[$file]['validators'] = array(); 0547 $this->_files[$file]['validated'] = false; 0548 } 0549 0550 return $this; 0551 } 0552 0553 /** 0554 * Sets Options for adapters 0555 * 0556 * @param array $options Options to set 0557 * @param array $files (Optional) Files to set the options for 0558 * @return Zend_File_Transfer_Adapter_Abstract 0559 */ 0560 public function setOptions($options = array(), $files = null) { 0561 $file = $this->_getFiles($files, false, true); 0562 0563 if (is_array($options)) { 0564 if (empty($file)) { 0565 $this->_options = array_merge($this->_options, $options); 0566 } 0567 0568 foreach ($options as $name => $value) { 0569 foreach ($file as $key => $content) { 0570 switch ($name) { 0571 case 'magicFile' : 0572 $this->_files[$key]['options'][$name] = (string) $value; 0573 break; 0574 0575 case 'ignoreNoFile' : 0576 case 'useByteString' : 0577 case 'detectInfos' : 0578 $this->_files[$key]['options'][$name] = (boolean) $value; 0579 break; 0580 0581 default: 0582 // require_once 'Zend/File/Transfer/Exception.php'; 0583 throw new Zend_File_Transfer_Exception("Unknown option: $name = $value"); 0584 } 0585 } 0586 } 0587 } 0588 0589 return $this; 0590 } 0591 0592 /** 0593 * Returns set options for adapters or files 0594 * 0595 * @param array $files (Optional) Files to return the options for 0596 * @return array Options for given files 0597 */ 0598 public function getOptions($files = null) { 0599 $file = $this->_getFiles($files, false, true); 0600 0601 foreach ($file as $key => $content) { 0602 if (isset($this->_files[$key]['options'])) { 0603 $options[$key] = $this->_files[$key]['options']; 0604 } else { 0605 $options[$key] = array(); 0606 } 0607 } 0608 0609 return $options; 0610 } 0611 0612 /** 0613 * Checks if the files are valid 0614 * 0615 * @param string|array $files (Optional) Files to check 0616 * @return boolean True if all checks are valid 0617 */ 0618 public function isValid($files = null) 0619 { 0620 $check = $this->_getFiles($files, false, true); 0621 if (empty($check)) { 0622 return false; 0623 } 0624 0625 $translator = $this->getTranslator(); 0626 $this->_messages = array(); 0627 $break = false; 0628 foreach($check as $key => $content) { 0629 if (array_key_exists('validators', $content) && 0630 in_array('Zend_Validate_File_Count', $content['validators'])) { 0631 $validator = $this->_validators['Zend_Validate_File_Count']; 0632 $count = $content; 0633 if (empty($content['tmp_name'])) { 0634 continue; 0635 } 0636 0637 if (array_key_exists('destination', $content)) { 0638 $checkit = $content['destination']; 0639 } else { 0640 $checkit = dirname($content['tmp_name']); 0641 } 0642 0643 $checkit .= DIRECTORY_SEPARATOR . $content['name']; 0644 $validator->addFile($checkit); 0645 } 0646 } 0647 0648 if (isset($count)) { 0649 if (!$validator->isValid($count['tmp_name'], $count)) { 0650 $this->_messages += $validator->getMessages(); 0651 } 0652 } 0653 0654 foreach ($check as $key => $content) { 0655 $fileerrors = array(); 0656 if (array_key_exists('validators', $content) && $content['validated']) { 0657 continue; 0658 } 0659 0660 if (array_key_exists('validators', $content)) { 0661 foreach ($content['validators'] as $class) { 0662 $validator = $this->_validators[$class]; 0663 if (method_exists($validator, 'setTranslator')) { 0664 $validator->setTranslator($translator); 0665 } 0666 0667 if (($class === 'Zend_Validate_File_Upload') and (empty($content['tmp_name']))) { 0668 $tocheck = $key; 0669 } else { 0670 $tocheck = $content['tmp_name']; 0671 } 0672 0673 if (!$validator->isValid($tocheck, $content)) { 0674 $fileerrors += $validator->getMessages(); 0675 } 0676 0677 if (!empty($content['options']['ignoreNoFile']) and (isset($fileerrors['fileUploadErrorNoFile']))) { 0678 unset($fileerrors['fileUploadErrorNoFile']); 0679 break; 0680 } 0681 0682 if (($class === 'Zend_Validate_File_Upload') and (count($fileerrors) > 0)) { 0683 break; 0684 } 0685 0686 if (($this->_break[$class]) and (count($fileerrors) > 0)) { 0687 $break = true; 0688 break; 0689 } 0690 } 0691 } 0692 0693 if (count($fileerrors) > 0) { 0694 $this->_files[$key]['validated'] = false; 0695 } else { 0696 $this->_files[$key]['validated'] = true; 0697 } 0698 0699 $this->_messages += $fileerrors; 0700 if ($break) { 0701 break; 0702 } 0703 } 0704 0705 if (count($this->_messages) > 0) { 0706 return false; 0707 } 0708 0709 return true; 0710 } 0711 0712 /** 0713 * Returns found validation messages 0714 * 0715 * @return array 0716 */ 0717 public function getMessages() 0718 { 0719 return $this->_messages; 0720 } 0721 0722 /** 0723 * Retrieve error codes 0724 * 0725 * @return array 0726 */ 0727 public function getErrors() 0728 { 0729 return array_keys($this->_messages); 0730 } 0731 0732 /** 0733 * Are there errors registered? 0734 * 0735 * @return boolean 0736 */ 0737 public function hasErrors() 0738 { 0739 return (!empty($this->_messages)); 0740 } 0741 0742 /** 0743 * Adds a new filter for this class 0744 * 0745 * @param string|array $filter Type of filter to add 0746 * @param string|array $options Options to set for the filter 0747 * @param string|array $files Files to limit this filter to 0748 * @return Zend_File_Transfer_Adapter 0749 */ 0750 public function addFilter($filter, $options = null, $files = null) 0751 { 0752 if ($filter instanceof Zend_Filter_Interface) { 0753 $class = get_class($filter); 0754 } elseif (is_string($filter)) { 0755 $class = $this->getPluginLoader(self::FILTER)->load($filter); 0756 $filter = new $class($options); 0757 } else { 0758 // require_once 'Zend/File/Transfer/Exception.php'; 0759 throw new Zend_File_Transfer_Exception('Invalid filter specified'); 0760 } 0761 0762 $this->_filters[$class] = $filter; 0763 $files = $this->_getFiles($files, true, true); 0764 foreach ($files as $file) { 0765 $this->_files[$file]['filters'][] = $class; 0766 } 0767 0768 return $this; 0769 } 0770 0771 /** 0772 * Add Multiple filters at once 0773 * 0774 * @param array $filters 0775 * @param string|array $files 0776 * @return Zend_File_Transfer_Adapter_Abstract 0777 */ 0778 public function addFilters(array $filters, $files = null) 0779 { 0780 foreach ($filters as $key => $spec) { 0781 if ($spec instanceof Zend_Filter_Interface) { 0782 $this->addFilter($spec, null, $files); 0783 continue; 0784 } 0785 0786 if (is_string($key)) { 0787 $this->addFilter($key, $spec, $files); 0788 continue; 0789 } 0790 0791 if (is_int($key)) { 0792 if (is_string($spec)) { 0793 $this->addFilter($spec, null, $files); 0794 continue; 0795 } 0796 0797 if (is_array($spec)) { 0798 if (!array_key_exists('filter', $spec)) { 0799 continue; 0800 } 0801 0802 $filter = $spec['filter']; 0803 unset($spec['filter']); 0804 $this->addFilter($filter, $spec, $files); 0805 continue; 0806 } 0807 0808 continue; 0809 } 0810 } 0811 0812 return $this; 0813 } 0814 0815 /** 0816 * Sets a filter for the class, erasing all previous set 0817 * 0818 * @param string|array $filter Filter to set 0819 * @param string|array $files Files to limit this filter to 0820 * @return Zend_File_Transfer_Adapter 0821 */ 0822 public function setFilters(array $filters, $files = null) 0823 { 0824 $this->clearFilters(); 0825 return $this->addFilters($filters, $files); 0826 } 0827 0828 /** 0829 * Determine if a given filter has already been registered 0830 * 0831 * @param string $name 0832 * @return bool 0833 */ 0834 public function hasFilter($name) 0835 { 0836 return (false !== $this->_getFilterIdentifier($name)); 0837 } 0838 0839 /** 0840 * Retrieve individual filter 0841 * 0842 * @param string $name 0843 * @return Zend_Filter_Interface|null 0844 */ 0845 public function getFilter($name) 0846 { 0847 if (false === ($identifier = $this->_getFilterIdentifier($name))) { 0848 return null; 0849 } 0850 return $this->_filters[$identifier]; 0851 } 0852 0853 /** 0854 * Returns all set filters 0855 * 0856 * @param string|array $files (Optional) Returns the filter for this files 0857 * @return array List of set filters 0858 * @throws Zend_File_Transfer_Exception When file not found 0859 */ 0860 public function getFilters($files = null) 0861 { 0862 if ($files === null) { 0863 return $this->_filters; 0864 } 0865 0866 $files = $this->_getFiles($files, true, true); 0867 $filters = array(); 0868 foreach ($files as $file) { 0869 if (!empty($this->_files[$file]['filters'])) { 0870 $filters += $this->_files[$file]['filters']; 0871 } 0872 } 0873 0874 $filters = array_unique($filters); 0875 $result = array(); 0876 foreach ($filters as $filter) { 0877 $result[] = $this->_filters[$filter]; 0878 } 0879 0880 return $result; 0881 } 0882 0883 /** 0884 * Remove an individual filter 0885 * 0886 * @param string $name 0887 * @return Zend_File_Transfer_Adapter_Abstract 0888 */ 0889 public function removeFilter($name) 0890 { 0891 if (false === ($key = $this->_getFilterIdentifier($name))) { 0892 return $this; 0893 } 0894 0895 unset($this->_filters[$key]); 0896 foreach (array_keys($this->_files) as $file) { 0897 if (empty($this->_files[$file]['filters'])) { 0898 continue; 0899 } 0900 0901 $index = array_search($key, $this->_files[$file]['filters']); 0902 if ($index === false) { 0903 continue; 0904 } 0905 0906 unset($this->_files[$file]['filters'][$index]); 0907 } 0908 return $this; 0909 } 0910 0911 /** 0912 * Remove all filters 0913 * 0914 * @return Zend_File_Transfer_Adapter_Abstract 0915 */ 0916 public function clearFilters() 0917 { 0918 $this->_filters = array(); 0919 foreach (array_keys($this->_files) as $file) { 0920 $this->_files[$file]['filters'] = array(); 0921 } 0922 return $this; 0923 } 0924 0925 /** 0926 * Returns all set files 0927 * 0928 * @return array List of set files 0929 * @throws Zend_File_Transfer_Exception Not implemented 0930 */ 0931 public function getFile() 0932 { 0933 // require_once 'Zend/File/Transfer/Exception.php'; 0934 throw new Zend_File_Transfer_Exception('Method not implemented'); 0935 } 0936 0937 /** 0938 * Retrieves the filename of transferred files. 0939 * 0940 * @param string|null $file 0941 * @param boolean $path (Optional) Should the path also be returned ? 0942 * @return string|array 0943 */ 0944 public function getFileName($file = null, $path = true) 0945 { 0946 $files = $this->_getFiles($file, true, true); 0947 $result = array(); 0948 $directory = ""; 0949 foreach($files as $file) { 0950 if (empty($this->_files[$file]['name'])) { 0951 continue; 0952 } 0953 0954 if ($path === true) { 0955 $directory = $this->getDestination($file) . DIRECTORY_SEPARATOR; 0956 } 0957 0958 $result[$file] = $directory . $this->_files[$file]['name']; 0959 } 0960 0961 if (count($result) == 1) { 0962 return current($result); 0963 } 0964 0965 return $result; 0966 } 0967 0968 /** 0969 * Retrieve additional internal file informations for files 0970 * 0971 * @param string $file (Optional) File to get informations for 0972 * @return array 0973 */ 0974 public function getFileInfo($file = null) 0975 { 0976 return $this->_getFiles($file); 0977 } 0978 0979 /** 0980 * Adds one or more files 0981 * 0982 * @param string|array $file File to add 0983 * @param string|array $validator Validators to use for this file, must be set before 0984 * @param string|array $filter Filters to use for this file, must be set before 0985 * @return Zend_File_Transfer_Adapter_Abstract 0986 * @throws Zend_File_Transfer_Exception Not implemented 0987 */ 0988 public function addFile($file, $validator = null, $filter = null) 0989 { 0990 // require_once 'Zend/File/Transfer/Exception.php'; 0991 throw new Zend_File_Transfer_Exception('Method not implemented'); 0992 } 0993 0994 /** 0995 * Returns all set types 0996 * 0997 * @return array List of set types 0998 * @throws Zend_File_Transfer_Exception Not implemented 0999 */ 1000 public function getType() 1001 { 1002 // require_once 'Zend/File/Transfer/Exception.php'; 1003 throw new Zend_File_Transfer_Exception('Method not implemented'); 1004 } 1005 1006 /** 1007 * Adds one or more type of files 1008 * 1009 * @param string|array $type Type of files to add 1010 * @param string|array $validator Validators to use for this file, must be set before 1011 * @param string|array $filter Filters to use for this file, must be set before 1012 * @return Zend_File_Transfer_Adapter_Abstract 1013 * @throws Zend_File_Transfer_Exception Not implemented 1014 */ 1015 public function addType($type, $validator = null, $filter = null) 1016 { 1017 // require_once 'Zend/File/Transfer/Exception.php'; 1018 throw new Zend_File_Transfer_Exception('Method not implemented'); 1019 } 1020 1021 /** 1022 * Sets a new destination for the given files 1023 * 1024 * @deprecated Will be changed to be a filter!!! 1025 * @param string $destination New destination directory 1026 * @param string|array $files Files to set the new destination for 1027 * @return Zend_File_Transfer_Abstract 1028 * @throws Zend_File_Transfer_Exception when the given destination is not a directory or does not exist 1029 */ 1030 public function setDestination($destination, $files = null) 1031 { 1032 $orig = $files; 1033 $destination = rtrim($destination, "/\\"); 1034 if (!is_dir($destination)) { 1035 // require_once 'Zend/File/Transfer/Exception.php'; 1036 throw new Zend_File_Transfer_Exception( 1037 'The given destination is not a directory or does not exist' 1038 ); 1039 } 1040 1041 if (!$this->_isPathWriteable($destination)) { 1042 // require_once 'Zend/File/Transfer/Exception.php'; 1043 throw new Zend_File_Transfer_Exception( 1044 'The given destination is not writable' 1045 ); 1046 } 1047 1048 if ($files === null) { 1049 foreach ($this->_files as $file => $content) { 1050 $this->_files[$file]['destination'] = $destination; 1051 } 1052 } else { 1053 $files = $this->_getFiles($files, true, true); 1054 if (empty($files) and is_string($orig)) { 1055 $this->_files[$orig]['destination'] = $destination; 1056 } 1057 1058 foreach ($files as $file) { 1059 $this->_files[$file]['destination'] = $destination; 1060 } 1061 } 1062 1063 return $this; 1064 } 1065 1066 /** 1067 * Retrieve destination directory value 1068 * 1069 * @param null|string|array $files 1070 * @return null|string|array 1071 * @throws Zend_File_Transfer_Exception 1072 */ 1073 public function getDestination($files = null) 1074 { 1075 $orig = $files; 1076 $files = $this->_getFiles($files, false, true); 1077 $destinations = array(); 1078 if (empty($files) and is_string($orig)) { 1079 if (isset($this->_files[$orig]['destination'])) { 1080 $destinations[$orig] = $this->_files[$orig]['destination']; 1081 } else { 1082 // require_once 'Zend/File/Transfer/Exception.php'; 1083 throw new Zend_File_Transfer_Exception(sprintf('The file transfer adapter can not find "%s"', $orig)); 1084 } 1085 } 1086 1087 foreach ($files as $key => $content) { 1088 if (isset($this->_files[$key]['destination'])) { 1089 $destinations[$key] = $this->_files[$key]['destination']; 1090 } else { 1091 $tmpdir = $this->_getTmpDir(); 1092 $this->setDestination($tmpdir, $key); 1093 $destinations[$key] = $tmpdir; 1094 } 1095 } 1096 1097 if (empty($destinations)) { 1098 $destinations = $this->_getTmpDir(); 1099 } else if (count($destinations) == 1) { 1100 $destinations = current($destinations); 1101 } 1102 1103 return $destinations; 1104 } 1105 1106 /** 1107 * Set translator object for localization 1108 * 1109 * @param Zend_Translate|null $translator 1110 * @return Zend_File_Transfer_Abstract 1111 * @throws Zend_File_Transfer_Exception 1112 */ 1113 public function setTranslator($translator = null) 1114 { 1115 if (null === $translator) { 1116 $this->_translator = null; 1117 } elseif ($translator instanceof Zend_Translate_Adapter) { 1118 $this->_translator = $translator; 1119 } elseif ($translator instanceof Zend_Translate) { 1120 $this->_translator = $translator->getAdapter(); 1121 } else { 1122 // require_once 'Zend/File/Transfer/Exception.php'; 1123 throw new Zend_File_Transfer_Exception('Invalid translator specified'); 1124 } 1125 1126 return $this; 1127 } 1128 1129 /** 1130 * Retrieve localization translator object 1131 * 1132 * @return Zend_Translate_Adapter|null 1133 */ 1134 public function getTranslator() 1135 { 1136 if ($this->translatorIsDisabled()) { 1137 return null; 1138 } 1139 1140 return $this->_translator; 1141 } 1142 1143 /** 1144 * Indicate whether or not translation should be disabled 1145 * 1146 * @param bool $flag 1147 * @return Zend_File_Transfer_Abstract 1148 */ 1149 public function setDisableTranslator($flag) 1150 { 1151 $this->_translatorDisabled = (bool) $flag; 1152 return $this; 1153 } 1154 1155 /** 1156 * Is translation disabled? 1157 * 1158 * @return bool 1159 */ 1160 public function translatorIsDisabled() 1161 { 1162 return $this->_translatorDisabled; 1163 } 1164 1165 /** 1166 * Returns the hash for a given file 1167 * 1168 * @param string $hash Hash algorithm to use 1169 * @param string|array $files Files to return the hash for 1170 * @return string|array Hashstring 1171 * @throws Zend_File_Transfer_Exception On unknown hash algorithm 1172 */ 1173 public function getHash($hash = 'crc32', $files = null) 1174 { 1175 if (!in_array($hash, hash_algos())) { 1176 // require_once 'Zend/File/Transfer/Exception.php'; 1177 throw new Zend_File_Transfer_Exception('Unknown hash algorithm'); 1178 } 1179 1180 $files = $this->_getFiles($files); 1181 $result = array(); 1182 foreach($files as $key => $value) { 1183 if (file_exists($value['name'])) { 1184 $result[$key] = hash_file($hash, $value['name']); 1185 } else if (file_exists($value['tmp_name'])) { 1186 $result[$key] = hash_file($hash, $value['tmp_name']); 1187 } else if (empty($value['options']['ignoreNoFile'])) { 1188 // require_once 'Zend/File/Transfer/Exception.php'; 1189 throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist"); 1190 } 1191 } 1192 1193 if (count($result) == 1) { 1194 return current($result); 1195 } 1196 1197 return $result; 1198 } 1199 1200 /** 1201 * Returns the real filesize of the file 1202 * 1203 * @param string|array $files Files to get the filesize from 1204 * @throws Zend_File_Transfer_Exception When the file does not exist 1205 * @return string|array Filesize 1206 */ 1207 public function getFileSize($files = null) 1208 { 1209 $files = $this->_getFiles($files); 1210 $result = array(); 1211 foreach($files as $key => $value) { 1212 if (file_exists($value['name']) || file_exists($value['tmp_name'])) { 1213 if ($value['options']['useByteString']) { 1214 $result[$key] = self::_toByteString($value['size']); 1215 } else { 1216 $result[$key] = $value['size']; 1217 } 1218 } else if (empty($value['options']['ignoreNoFile'])) { 1219 // require_once 'Zend/File/Transfer/Exception.php'; 1220 throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist"); 1221 } else { 1222 continue; 1223 } 1224 } 1225 1226 if (count($result) == 1) { 1227 return current($result); 1228 } 1229 1230 return $result; 1231 } 1232 1233 /** 1234 * Internal method to detect the size of a file 1235 * 1236 * @param array $value File infos 1237 * @return string Filesize of given file 1238 */ 1239 protected function _detectFileSize($value) 1240 { 1241 if (file_exists($value['name'])) { 1242 $result = sprintf("%u", @filesize($value['name'])); 1243 } else if (file_exists($value['tmp_name'])) { 1244 $result = sprintf("%u", @filesize($value['tmp_name'])); 1245 } else { 1246 return null; 1247 } 1248 1249 return $result; 1250 } 1251 1252 /** 1253 * Returns the real mimetype of the file 1254 * Uses fileinfo, when not available mime_magic and as last fallback a manual given mimetype 1255 * 1256 * @param string|array $files Files to get the mimetype from 1257 * @throws Zend_File_Transfer_Exception When the file does not exist 1258 * @return string|array MimeType 1259 */ 1260 public function getMimeType($files = null) 1261 { 1262 $files = $this->_getFiles($files); 1263 $result = array(); 1264 foreach($files as $key => $value) { 1265 if (file_exists($value['name']) || file_exists($value['tmp_name'])) { 1266 $result[$key] = $value['type']; 1267 } else if (empty($value['options']['ignoreNoFile'])) { 1268 // require_once 'Zend/File/Transfer/Exception.php'; 1269 throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist"); 1270 } else { 1271 continue; 1272 } 1273 } 1274 1275 if (count($result) == 1) { 1276 return current($result); 1277 } 1278 1279 return $result; 1280 } 1281 1282 /** 1283 * Internal method to detect the mime type of a file 1284 * 1285 * @param array $value File infos 1286 * @return string Mimetype of given file 1287 */ 1288 protected function _detectMimeType($value) 1289 { 1290 if (file_exists($value['name'])) { 1291 $file = $value['name']; 1292 } else if (file_exists($value['tmp_name'])) { 1293 $file = $value['tmp_name']; 1294 } else { 1295 return null; 1296 } 1297 1298 if (class_exists('finfo', false)) { 1299 $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME; 1300 if (!empty($value['options']['magicFile'])) { 1301 $mime = @finfo_open($const, $value['options']['magicFile']); 1302 } 1303 1304 if (empty($mime)) { 1305 $mime = @finfo_open($const); 1306 } 1307 1308 if (!empty($mime)) { 1309 $result = finfo_file($mime, $file); 1310 } 1311 1312 unset($mime); 1313 } 1314 1315 if (empty($result) && (function_exists('mime_content_type') 1316 && ini_get('mime_magic.magicfile'))) { 1317 $result = mime_content_type($file); 1318 } 1319 1320 if (empty($result)) { 1321 $result = 'application/octet-stream'; 1322 } 1323 1324 return $result; 1325 } 1326 1327 /** 1328 * Returns the formatted size 1329 * 1330 * @param integer $size 1331 * @return string 1332 */ 1333 protected static function _toByteString($size) 1334 { 1335 $sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'); 1336 for ($i=0; $size >= 1024 && $i < 9; $i++) { 1337 $size /= 1024; 1338 } 1339 1340 return round($size, 2) . $sizes[$i]; 1341 } 1342 1343 /** 1344 * Internal function to filter all given files 1345 * 1346 * @param string|array $files (Optional) Files to check 1347 * @return boolean False on error 1348 */ 1349 protected function _filter($files = null) 1350 { 1351 $check = $this->_getFiles($files); 1352 foreach ($check as $name => $content) { 1353 if (array_key_exists('filters', $content)) { 1354 foreach ($content['filters'] as $class) { 1355 $filter = $this->_filters[$class]; 1356 try { 1357 $result = $filter->filter($this->getFileName($name)); 1358 1359 $this->_files[$name]['destination'] = dirname($result); 1360 $this->_files[$name]['name'] = basename($result); 1361 } catch (Zend_Filter_Exception $e) { 1362 $this->_messages += array($e->getMessage()); 1363 } 1364 } 1365 } 1366 } 1367 1368 if (count($this->_messages) > 0) { 1369 return false; 1370 } 1371 1372 return true; 1373 } 1374 1375 /** 1376 * Determine system TMP directory and detect if we have read access 1377 * 1378 * @return string 1379 * @throws Zend_File_Transfer_Exception if unable to determine directory 1380 */ 1381 protected function _getTmpDir() 1382 { 1383 if (null === $this->_tmpDir) { 1384 $tmpdir = array(); 1385 if (function_exists('sys_get_temp_dir')) { 1386 $tmpdir[] = sys_get_temp_dir(); 1387 } 1388 1389 if (!empty($_ENV['TMP'])) { 1390 $tmpdir[] = realpath($_ENV['TMP']); 1391 } 1392 1393 if (!empty($_ENV['TMPDIR'])) { 1394 $tmpdir[] = realpath($_ENV['TMPDIR']); 1395 } 1396 1397 if (!empty($_ENV['TEMP'])) { 1398 $tmpdir[] = realpath($_ENV['TEMP']); 1399 } 1400 1401 $upload = ini_get('upload_tmp_dir'); 1402 if ($upload) { 1403 $tmpdir[] = realpath($upload); 1404 } 1405 1406 foreach($tmpdir as $directory) { 1407 if ($this->_isPathWriteable($directory)) { 1408 $this->_tmpDir = $directory; 1409 } 1410 } 1411 1412 if (empty($this->_tmpDir)) { 1413 // Attemp to detect by creating a temporary file 1414 $tempFile = tempnam(md5(uniqid(rand(), TRUE)), ''); 1415 if ($tempFile) { 1416 $this->_tmpDir = realpath(dirname($tempFile)); 1417 unlink($tempFile); 1418 } else { 1419 // require_once 'Zend/File/Transfer/Exception.php'; 1420 throw new Zend_File_Transfer_Exception('Could not determine a temporary directory'); 1421 } 1422 } 1423 1424 $this->_tmpDir = rtrim($this->_tmpDir, "/\\"); 1425 } 1426 return $this->_tmpDir; 1427 } 1428 1429 /** 1430 * Tries to detect if we can read and write to the given path 1431 * 1432 * @param string $path 1433 * @return bool 1434 */ 1435 protected function _isPathWriteable($path) 1436 { 1437 $tempFile = rtrim($path, "/\\"); 1438 $tempFile .= '/' . 'test.1'; 1439 1440 $result = @file_put_contents($tempFile, 'TEST'); 1441 1442 if ($result == false) { 1443 return false; 1444 } 1445 1446 $result = @unlink($tempFile); 1447 1448 if ($result == false) { 1449 return false; 1450 } 1451 1452 return true; 1453 } 1454 1455 /** 1456 * Returns found files based on internal file array and given files 1457 * 1458 * @param string|array $files (Optional) Files to return 1459 * @param boolean $names (Optional) Returns only names on true, else complete info 1460 * @param boolean $noexception (Optional) Allows throwing an exception, otherwise returns an empty array 1461 * @return array Found files 1462 * @throws Zend_File_Transfer_Exception On false filename 1463 */ 1464 protected function _getFiles($files, $names = false, $noexception = false) 1465 { 1466 $check = array(); 1467 1468 if (is_string($files)) { 1469 $files = array($files); 1470 } 1471 1472 if (is_array($files)) { 1473 foreach ($files as $find) { 1474 $found = array(); 1475 foreach ($this->_files as $file => $content) { 1476 if (!isset($content['name'])) { 1477 continue; 1478 } 1479 1480 if (($content['name'] === $find) && isset($content['multifiles'])) { 1481 foreach ($content['multifiles'] as $multifile) { 1482 $found[] = $multifile; 1483 } 1484 break; 1485 } 1486 1487 if ($file === $find) { 1488 $found[] = $file; 1489 break; 1490 } 1491 1492 if ($content['name'] === $find) { 1493 $found[] = $file; 1494 break; 1495 } 1496 } 1497 1498 if (empty($found)) { 1499 if ($noexception !== false) { 1500 return array(); 1501 } 1502 1503 // require_once 'Zend/File/Transfer/Exception.php'; 1504 throw new Zend_File_Transfer_Exception(sprintf('The file transfer adapter can not find "%s"', $find)); 1505 } 1506 1507 foreach ($found as $checked) { 1508 $check[$checked] = $this->_files[$checked]; 1509 } 1510 } 1511 } 1512 1513 if ($files === null) { 1514 $check = $this->_files; 1515 $keys = array_keys($check); 1516 foreach ($keys as $key) { 1517 if (isset($check[$key]['multifiles'])) { 1518 unset($check[$key]); 1519 } 1520 } 1521 } 1522 1523 if ($names) { 1524 $check = array_keys($check); 1525 } 1526 1527 return $check; 1528 } 1529 1530 /** 1531 * Retrieve internal identifier for a named validator 1532 * 1533 * @param string $name 1534 * @return string 1535 */ 1536 protected function _getValidatorIdentifier($name) 1537 { 1538 if (array_key_exists($name, $this->_validators)) { 1539 return $name; 1540 } 1541 1542 foreach (array_keys($this->_validators) as $test) { 1543 if (preg_match('/' . preg_quote($name) . '$/i', $test)) { 1544 return $test; 1545 } 1546 } 1547 1548 return false; 1549 } 1550 1551 /** 1552 * Retrieve internal identifier for a named filter 1553 * 1554 * @param string $name 1555 * @return string 1556 */ 1557 protected function _getFilterIdentifier($name) 1558 { 1559 if (array_key_exists($name, $this->_filters)) { 1560 return $name; 1561 } 1562 1563 foreach (array_keys($this->_filters) as $test) { 1564 if (preg_match('/' . preg_quote($name) . '$/i', $test)) { 1565 return $test; 1566 } 1567 } 1568 1569 return false; 1570 } 1571 }