PageRenderTime 446ms CodeModel.GetById 131ms app.highlight 194ms RepoModel.GetById 107ms app.codeStats 1ms

/lib/Zend/File/Transfer/Adapter/Abstract.php

https://bitbucket.org/andrewjleavitt/magestudy
PHP | 1563 lines | 897 code | 179 blank | 487 comment | 185 complexity | 68781d51a4549fbb1f2f10b408693b2c MD5 | raw file
   1<?php
   2/**
   3 * Zend Framework
   4 *
   5 * LICENSE
   6 *
   7 * This source file is subject to the new BSD license that is bundled
   8 * with this package in the file LICENSE.txt.
   9 * It is also available through the world-wide-web at this URL:
  10 * http://framework.zend.com/license/new-bsd
  11 * If you did not receive a copy of the license and are unable to
  12 * obtain it through the world-wide-web, please send an email
  13 * to license@zend.com so we can send you a copy immediately.
  14 *
  15 * @category  Zend
  16 * @package   Zend_File_Transfer
  17 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  18 * @license   http://framework.zend.com/license/new-bsd     New BSD License
  19 * @version   $Id: Abstract.php 22371 2010-06-04 20:09:44Z thomas $
  20 */
  21
  22/**
  23 * Abstract class for file transfers (Downloads and Uploads)
  24 *
  25 * @category  Zend
  26 * @package   Zend_File_Transfer
  27 * @copyright  Copyright (c) 2005-2010 Zend Technologies USA Inc. (http://www.zend.com)
  28 * @license   http://framework.zend.com/license/new-bsd     New BSD License
  29 */
  30abstract class Zend_File_Transfer_Adapter_Abstract
  31{
  32    /**@+
  33     * Plugin loader Constants
  34     */
  35    const FILTER    = 'FILTER';
  36    const VALIDATE  = 'VALIDATE';
  37    /**@-*/
  38
  39    /**
  40     * Internal list of breaks
  41     *
  42     * @var array
  43     */
  44    protected $_break = array();
  45
  46    /**
  47     * Internal list of filters
  48     *
  49     * @var array
  50     */
  51    protected $_filters = array();
  52
  53    /**
  54     * Plugin loaders for filter and validation chains
  55     *
  56     * @var array
  57     */
  58    protected $_loaders = array();
  59
  60    /**
  61     * Internal list of messages
  62     *
  63     * @var array
  64     */
  65    protected $_messages = array();
  66
  67    /**
  68     * @var Zend_Translate
  69     */
  70    protected $_translator;
  71
  72    /**
  73     * Is translation disabled?
  74     *
  75     * @var bool
  76     */
  77    protected $_translatorDisabled = false;
  78
  79    /**
  80     * Internal list of validators
  81     * @var array
  82     */
  83    protected $_validators = array();
  84
  85    /**
  86     * Internal list of files
  87     * This array looks like this:
  88     *     array(form => array( - Form is the name within the form or, if not set the filename
  89     *         name,            - Original name of this file
  90     *         type,            - Mime type of this file
  91     *         size,            - Filesize in bytes
  92     *         tmp_name,        - Internalally temporary filename for uploaded files
  93     *         error,           - Error which has occured
  94     *         destination,     - New destination for this file
  95     *         validators,      - Set validator names for this file
  96     *         files            - Set file names for this file
  97     *     ))
  98     *
  99     * @var array
 100     */
 101    protected $_files = array();
 102
 103    /**
 104     * TMP directory
 105     * @var string
 106     */
 107    protected $_tmpDir;
 108
 109    /**
 110     * Available options for file transfers
 111     */
 112    protected $_options = array(
 113        'ignoreNoFile'  => false,
 114        'useByteString' => true,
 115        'magicFile'     => null,
 116        'detectInfos'   => true,
 117    );
 118
 119    /**
 120     * Send file
 121     *
 122     * @param  mixed $options
 123     * @return bool
 124     */
 125    abstract public function send($options = null);
 126
 127    /**
 128     * Receive file
 129     *
 130     * @param  mixed $options
 131     * @return bool
 132     */
 133    abstract public function receive($options = null);
 134
 135    /**
 136     * Is file sent?
 137     *
 138     * @param  array|string|null $files
 139     * @return bool
 140     */
 141    abstract public function isSent($files = null);
 142
 143    /**
 144     * Is file received?
 145     *
 146     * @param  array|string|null $files
 147     * @return bool
 148     */
 149    abstract public function isReceived($files = null);
 150
 151    /**
 152     * Has a file been uploaded ?
 153     *
 154     * @param  array|string|null $files
 155     * @return bool
 156     */
 157    abstract public function isUploaded($files = null);
 158
 159    /**
 160     * Has the file been filtered ?
 161     *
 162     * @param array|string|null $files
 163     * @return bool
 164     */
 165    abstract public function isFiltered($files = null);
 166
 167    /**
 168     * Retrieve progress of transfer
 169     *
 170     * @return float
 171     */
 172    public static function getProgress()
 173    {
 174        #require_once 'Zend/File/Transfer/Exception.php';
 175        throw new Zend_File_Transfer_Exception('Method must be implemented within the adapter');
 176    }
 177
 178    /**
 179     * Set plugin loader to use for validator or filter chain
 180     *
 181     * @param  Zend_Loader_PluginLoader_Interface $loader
 182     * @param  string $type 'filter', or 'validate'
 183     * @return Zend_File_Transfer_Adapter_Abstract
 184     * @throws Zend_File_Transfer_Exception on invalid type
 185     */
 186    public function setPluginLoader(Zend_Loader_PluginLoader_Interface $loader, $type)
 187    {
 188        $type = strtoupper($type);
 189        switch ($type) {
 190            case self::FILTER:
 191            case self::VALIDATE:
 192                $this->_loaders[$type] = $loader;
 193                return $this;
 194            default:
 195                #require_once 'Zend/File/Transfer/Exception.php';
 196                throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to setPluginLoader()', $type));
 197        }
 198    }
 199
 200    /**
 201     * Retrieve plugin loader for validator or filter chain
 202     *
 203     * Instantiates with default rules if none available for that type. Use
 204     * 'filter' or 'validate' for $type.
 205     *
 206     * @param  string $type
 207     * @return Zend_Loader_PluginLoader
 208     * @throws Zend_File_Transfer_Exception on invalid type.
 209     */
 210    public function getPluginLoader($type)
 211    {
 212        $type = strtoupper($type);
 213        switch ($type) {
 214            case self::FILTER:
 215            case self::VALIDATE:
 216                $prefixSegment = ucfirst(strtolower($type));
 217                $pathSegment   = $prefixSegment;
 218                if (!isset($this->_loaders[$type])) {
 219                    $paths         = array(
 220                        'Zend_' . $prefixSegment . '_'     => 'Zend/' . $pathSegment . '/',
 221                        'Zend_' . $prefixSegment . '_File' => 'Zend/' . $pathSegment . '/File',
 222                    );
 223
 224                    #require_once 'Zend/Loader/PluginLoader.php';
 225                    $this->_loaders[$type] = new Zend_Loader_PluginLoader($paths);
 226                } else {
 227                    $loader = $this->_loaders[$type];
 228                    $prefix = 'Zend_' . $prefixSegment . '_File_';
 229                    if (!$loader->getPaths($prefix)) {
 230                        $loader->addPrefixPath($prefix, str_replace('_', '/', $prefix));
 231                    }
 232                }
 233                return $this->_loaders[$type];
 234            default:
 235                #require_once 'Zend/File/Transfer/Exception.php';
 236                throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
 237        }
 238    }
 239
 240    /**
 241     * Add prefix path for plugin loader
 242     *
 243     * If no $type specified, assumes it is a base path for both filters and
 244     * validators, and sets each according to the following rules:
 245     * - filters:    $prefix = $prefix . '_Filter'
 246     * - validators: $prefix = $prefix . '_Validate'
 247     *
 248     * Otherwise, the path prefix is set on the appropriate plugin loader.
 249     *
 250     * @param  string $prefix
 251     * @param  string $path
 252     * @param  string $type
 253     * @return Zend_File_Transfer_Adapter_Abstract
 254     * @throws Zend_File_Transfer_Exception for invalid type
 255     */
 256    public function addPrefixPath($prefix, $path, $type = null)
 257    {
 258        $type = strtoupper($type);
 259        switch ($type) {
 260            case self::FILTER:
 261            case self::VALIDATE:
 262                $loader = $this->getPluginLoader($type);
 263                $loader->addPrefixPath($prefix, $path);
 264                return $this;
 265            case null:
 266                $prefix = rtrim($prefix, '_');
 267                $path   = rtrim($path, DIRECTORY_SEPARATOR);
 268                foreach (array(self::FILTER, self::VALIDATE) as $type) {
 269                    $cType        = ucfirst(strtolower($type));
 270                    $pluginPath   = $path . DIRECTORY_SEPARATOR . $cType . DIRECTORY_SEPARATOR;
 271                    $pluginPrefix = $prefix . '_' . $cType;
 272                    $loader       = $this->getPluginLoader($type);
 273                    $loader->addPrefixPath($pluginPrefix, $pluginPath);
 274                }
 275                return $this;
 276            default:
 277                #require_once 'Zend/File/Transfer/Exception.php';
 278                throw new Zend_File_Transfer_Exception(sprintf('Invalid type "%s" provided to getPluginLoader()', $type));
 279        }
 280    }
 281
 282    /**
 283     * Add many prefix paths at once
 284     *
 285     * @param  array $spec
 286     * @return Zend_File_Transfer_Exception
 287     */
 288    public function addPrefixPaths(array $spec)
 289    {
 290        if (isset($spec['prefix']) && isset($spec['path'])) {
 291            return $this->addPrefixPath($spec['prefix'], $spec['path']);
 292        }
 293        foreach ($spec as $type => $paths) {
 294            if (is_numeric($type) && is_array($paths)) {
 295                $type = null;
 296                if (isset($paths['prefix']) && isset($paths['path'])) {
 297                    if (isset($paths['type'])) {
 298                        $type = $paths['type'];
 299                    }
 300                    $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
 301                }
 302            } elseif (!is_numeric($type)) {
 303                if (!isset($paths['prefix']) || !isset($paths['path'])) {
 304                    foreach ($paths as $prefix => $spec) {
 305                        if (is_array($spec)) {
 306                            foreach ($spec as $path) {
 307                                if (!is_string($path)) {
 308                                    continue;
 309                                }
 310                                $this->addPrefixPath($prefix, $path, $type);
 311                            }
 312                        } elseif (is_string($spec)) {
 313                            $this->addPrefixPath($prefix, $spec, $type);
 314                        }
 315                    }
 316                } else {
 317                    $this->addPrefixPath($paths['prefix'], $paths['path'], $type);
 318                }
 319            }
 320        }
 321        return $this;
 322    }
 323
 324    /**
 325     * Adds a new validator for this class
 326     *
 327     * @param  string|array $validator           Type of validator to add
 328     * @param  boolean      $breakChainOnFailure If the validation chain should stop an failure
 329     * @param  string|array $options             Options to set for the validator
 330     * @param  string|array $files               Files to limit this validator to
 331     * @return Zend_File_Transfer_Adapter
 332     */
 333    public function addValidator($validator, $breakChainOnFailure = false, $options = null, $files = null)
 334    {
 335        if ($validator instanceof Zend_Validate_Interface) {
 336            $name = get_class($validator);
 337        } elseif (is_string($validator)) {
 338            $name      = $this->getPluginLoader(self::VALIDATE)->load($validator);
 339            $validator = new $name($options);
 340            if (is_array($options) && isset($options['messages'])) {
 341                if (is_array($options['messages'])) {
 342                    $validator->setMessages($options['messages']);
 343                } elseif (is_string($options['messages'])) {
 344                    $validator->setMessage($options['messages']);
 345                }
 346
 347                unset($options['messages']);
 348            }
 349        } else {
 350            #require_once 'Zend/File/Transfer/Exception.php';
 351            throw new Zend_File_Transfer_Exception('Invalid validator provided to addValidator; must be string or Zend_Validate_Interface');
 352        }
 353
 354        $this->_validators[$name] = $validator;
 355        $this->_break[$name]      = $breakChainOnFailure;
 356        $files                    = $this->_getFiles($files, true, true);
 357        foreach ($files as $file) {
 358            if ($name == 'NotEmpty') {
 359                $temp = $this->_files[$file]['validators'];
 360                $this->_files[$file]['validators']  = array($name);
 361                $this->_files[$file]['validators'] += $temp;
 362            } else {
 363                $this->_files[$file]['validators'][] = $name;
 364            }
 365
 366            $this->_files[$file]['validated']    = false;
 367        }
 368
 369        return $this;
 370    }
 371
 372    /**
 373     * Add Multiple validators at once
 374     *
 375     * @param  array $validators
 376     * @param  string|array $files
 377     * @return Zend_File_Transfer_Adapter_Abstract
 378     */
 379    public function addValidators(array $validators, $files = null)
 380    {
 381        foreach ($validators as $name => $validatorInfo) {
 382            if ($validatorInfo instanceof Zend_Validate_Interface) {
 383                $this->addValidator($validatorInfo, null, null, $files);
 384            } else if (is_string($validatorInfo)) {
 385                if (!is_int($name)) {
 386                    $this->addValidator($name, null, $validatorInfo, $files);
 387                } else {
 388                    $this->addValidator($validatorInfo, null, null, $files);
 389                }
 390            } else if (is_array($validatorInfo)) {
 391                $argc                = count($validatorInfo);
 392                $breakChainOnFailure = false;
 393                $options             = array();
 394                if (isset($validatorInfo['validator'])) {
 395                    $validator = $validatorInfo['validator'];
 396                    if (isset($validatorInfo['breakChainOnFailure'])) {
 397                        $breakChainOnFailure = $validatorInfo['breakChainOnFailure'];
 398                    }
 399
 400                    if (isset($validatorInfo['options'])) {
 401                        $options = $validatorInfo['options'];
 402                    }
 403
 404                    $this->addValidator($validator, $breakChainOnFailure, $options, $files);
 405                } else {
 406                    if (is_string($name)) {
 407                        $validator = $name;
 408                        $options   = $validatorInfo;
 409                        $this->addValidator($validator, $breakChainOnFailure, $options, $files);
 410                    } else {
 411                        $file = $files;
 412                        switch (true) {
 413                            case (0 == $argc):
 414                                break;
 415                            case (1 <= $argc):
 416                                $validator  = array_shift($validatorInfo);
 417                            case (2 <= $argc):
 418                                $breakChainOnFailure = array_shift($validatorInfo);
 419                            case (3 <= $argc):
 420                                $options = array_shift($validatorInfo);
 421                            case (4 <= $argc):
 422                                if (!empty($validatorInfo)) {
 423                                    $file = array_shift($validatorInfo);
 424                                }
 425                            default:
 426                                $this->addValidator($validator, $breakChainOnFailure, $options, $file);
 427                                break;
 428                        }
 429                    }
 430                }
 431            } else {
 432                #require_once 'Zend/File/Transfer/Exception.php';
 433                throw new Zend_File_Transfer_Exception('Invalid validator passed to addValidators()');
 434            }
 435        }
 436
 437        return $this;
 438    }
 439
 440    /**
 441     * Sets a validator for the class, erasing all previous set
 442     *
 443     * @param  string|array $validator Validator to set
 444     * @param  string|array $files     Files to limit this validator to
 445     * @return Zend_File_Transfer_Adapter
 446     */
 447    public function setValidators(array $validators, $files = null)
 448    {
 449        $this->clearValidators();
 450        return $this->addValidators($validators, $files);
 451    }
 452
 453    /**
 454     * Determine if a given validator has already been registered
 455     *
 456     * @param  string $name
 457     * @return bool
 458     */
 459    public function hasValidator($name)
 460    {
 461        return (false !== $this->_getValidatorIdentifier($name));
 462    }
 463
 464    /**
 465     * Retrieve individual validator
 466     *
 467     * @param  string $name
 468     * @return Zend_Validate_Interface|null
 469     */
 470    public function getValidator($name)
 471    {
 472        if (false === ($identifier = $this->_getValidatorIdentifier($name))) {
 473            return null;
 474        }
 475        return $this->_validators[$identifier];
 476    }
 477
 478    /**
 479     * Returns all set validators
 480     *
 481     * @param  string|array $files (Optional) Returns the validator for this files
 482     * @return null|array List of set validators
 483     */
 484    public function getValidators($files = null)
 485    {
 486        if ($files == null) {
 487            return $this->_validators;
 488        }
 489
 490        $files      = $this->_getFiles($files, true, true);
 491        $validators = array();
 492        foreach ($files as $file) {
 493            if (!empty($this->_files[$file]['validators'])) {
 494                $validators += $this->_files[$file]['validators'];
 495            }
 496        }
 497
 498        $validators = array_unique($validators);
 499        $result     = array();
 500        foreach ($validators as $validator) {
 501            $result[$validator] = $this->_validators[$validator];
 502        }
 503
 504        return $result;
 505    }
 506
 507    /**
 508     * Remove an individual validator
 509     *
 510     * @param  string $name
 511     * @return Zend_File_Transfer_Adapter_Abstract
 512     */
 513    public function removeValidator($name)
 514    {
 515        if (false === ($key = $this->_getValidatorIdentifier($name))) {
 516            return $this;
 517        }
 518
 519        unset($this->_validators[$key]);
 520        foreach (array_keys($this->_files) as $file) {
 521            if (empty($this->_files[$file]['validators'])) {
 522                continue;
 523            }
 524
 525            $index = array_search($key, $this->_files[$file]['validators']);
 526            if ($index === false) {
 527                continue;
 528            }
 529
 530            unset($this->_files[$file]['validators'][$index]);
 531            $this->_files[$file]['validated'] = false;
 532        }
 533
 534        return $this;
 535    }
 536
 537    /**
 538     * Remove all validators
 539     *
 540     * @return Zend_File_Transfer_Adapter_Abstract
 541     */
 542    public function clearValidators()
 543    {
 544        $this->_validators = array();
 545        foreach (array_keys($this->_files) as $file) {
 546            $this->_files[$file]['validators'] = array();
 547            $this->_files[$file]['validated']  = false;
 548        }
 549
 550        return $this;
 551    }
 552
 553    /**
 554     * Sets Options for adapters
 555     *
 556     * @param array $options Options to set
 557     * @param array $files   (Optional) Files to set the options for
 558     */
 559    public function setOptions($options = array(), $files = null) {
 560        $file = $this->_getFiles($files, false, true);
 561
 562        if (is_array($options)) {
 563            if (empty($file)) {
 564                $this->_options = array_merge($this->_options, $options);
 565            }
 566
 567            foreach ($options as $name => $value) {
 568                foreach ($file as $key => $content) {
 569                    switch ($name) {
 570                        case 'magicFile' :
 571                            $this->_files[$key]['options'][$name] = (string) $value;
 572                            break;
 573
 574                        case 'ignoreNoFile' :
 575                        case 'useByteString' :
 576                        case 'detectInfos' :
 577                            $this->_files[$key]['options'][$name] = (boolean) $value;
 578                            break;
 579
 580                        default:
 581                            #require_once 'Zend/File/Transfer/Exception.php';
 582                            throw new Zend_File_Transfer_Exception("Unknown option: $name = $value");
 583                    }
 584                }
 585            }
 586        }
 587
 588        return $this;
 589    }
 590
 591    /**
 592     * Returns set options for adapters or files
 593     *
 594     * @param  array $files (Optional) Files to return the options for
 595     * @return array Options for given files
 596     */
 597    public function getOptions($files = null) {
 598        $file = $this->_getFiles($files, false, true);
 599
 600        foreach ($file as $key => $content) {
 601            if (isset($this->_files[$key]['options'])) {
 602                $options[$key] = $this->_files[$key]['options'];
 603            } else {
 604                $options[$key] = array();
 605            }
 606        }
 607
 608        return $options;
 609    }
 610
 611    /**
 612     * Checks if the files are valid
 613     *
 614     * @param  string|array $files (Optional) Files to check
 615     * @return boolean True if all checks are valid
 616     */
 617    public function isValid($files = null)
 618    {
 619        $check = $this->_getFiles($files, false, true);
 620        if (empty($check)) {
 621            return false;
 622        }
 623
 624        $translator      = $this->getTranslator();
 625        $this->_messages = array();
 626        $break           = false;
 627        foreach($check as $key => $content) {
 628            if (array_key_exists('validators', $content) &&
 629                in_array('Zend_Validate_File_Count', $content['validators'])) {
 630                $validator = $this->_validators['Zend_Validate_File_Count'];
 631                $count     = $content;
 632                if (empty($content['tmp_name'])) {
 633                    continue;
 634                }
 635
 636                if (array_key_exists('destination', $content)) {
 637                    $checkit = $content['destination'];
 638                } else {
 639                    $checkit = dirname($content['tmp_name']);
 640                }
 641
 642                $checkit .= DIRECTORY_SEPARATOR . $content['name'];
 643                    $validator->addFile($checkit);
 644            }
 645        }
 646
 647        if (isset($count)) {
 648            if (!$validator->isValid($count['tmp_name'], $count)) {
 649                $this->_messages += $validator->getMessages();
 650            }
 651        }
 652
 653        foreach ($check as $key => $content) {
 654            $fileerrors  = array();
 655            if (array_key_exists('validators', $content) && $content['validated']) {
 656                continue;
 657            }
 658
 659            if (array_key_exists('validators', $content)) {
 660                foreach ($content['validators'] as $class) {
 661                    $validator = $this->_validators[$class];
 662                    if (method_exists($validator, 'setTranslator')) {
 663                        $validator->setTranslator($translator);
 664                    }
 665
 666                    if (($class === 'Zend_Validate_File_Upload') and (empty($content['tmp_name']))) {
 667                        $tocheck = $key;
 668                    } else {
 669                        $tocheck = $content['tmp_name'];
 670                    }
 671
 672                    if (!$validator->isValid($tocheck, $content)) {
 673                        $fileerrors += $validator->getMessages();
 674                    }
 675
 676                    if (!empty($content['options']['ignoreNoFile']) and (isset($fileerrors['fileUploadErrorNoFile']))) {
 677                        unset($fileerrors['fileUploadErrorNoFile']);
 678                        break;
 679                    }
 680
 681                    if (($class === 'Zend_Validate_File_Upload') and (count($fileerrors) > 0)) {
 682                        break;
 683                    }
 684
 685                    if (($this->_break[$class]) and (count($fileerrors) > 0)) {
 686                        $break = true;
 687                        break;
 688                    }
 689                }
 690            }
 691
 692            if (count($fileerrors) > 0) {
 693                $this->_files[$key]['validated'] = false;
 694            } else {
 695                $this->_files[$key]['validated'] = true;
 696            }
 697
 698            $this->_messages += $fileerrors;
 699            if ($break) {
 700                break;
 701            }
 702        }
 703
 704        if (count($this->_messages) > 0) {
 705            return false;
 706        }
 707
 708        return true;
 709    }
 710
 711    /**
 712     * Returns found validation messages
 713     *
 714     * @return array
 715     */
 716    public function getMessages()
 717    {
 718        return $this->_messages;
 719    }
 720
 721    /**
 722     * Retrieve error codes
 723     *
 724     * @return array
 725     */
 726    public function getErrors()
 727    {
 728        return array_keys($this->_messages);
 729    }
 730
 731    /**
 732     * Are there errors registered?
 733     *
 734     * @return boolean
 735     */
 736    public function hasErrors()
 737    {
 738        return (!empty($this->_messages));
 739    }
 740
 741    /**
 742     * Adds a new filter for this class
 743     *
 744     * @param  string|array $filter Type of filter to add
 745     * @param  string|array $options   Options to set for the filter
 746     * @param  string|array $files     Files to limit this filter to
 747     * @return Zend_File_Transfer_Adapter
 748     */
 749    public function addFilter($filter, $options = null, $files = null)
 750    {
 751        if ($filter instanceof Zend_Filter_Interface) {
 752            $class = get_class($filter);
 753        } elseif (is_string($filter)) {
 754            $class  = $this->getPluginLoader(self::FILTER)->load($filter);
 755            $filter = new $class($options);
 756        } else {
 757            #require_once 'Zend/File/Transfer/Exception.php';
 758            throw new Zend_File_Transfer_Exception('Invalid filter specified');
 759        }
 760
 761        $this->_filters[$class] = $filter;
 762        $files                  = $this->_getFiles($files, true, true);
 763        foreach ($files as $file) {
 764            $this->_files[$file]['filters'][] = $class;
 765        }
 766
 767        return $this;
 768    }
 769
 770    /**
 771     * Add Multiple filters at once
 772     *
 773     * @param  array $filters
 774     * @param  string|array $files
 775     * @return Zend_File_Transfer_Adapter_Abstract
 776     */
 777    public function addFilters(array $filters, $files = null)
 778    {
 779        foreach ($filters as $key => $spec) {
 780            if ($spec instanceof Zend_Filter_Interface) {
 781                $this->addFilter($spec, null, $files);
 782                continue;
 783            }
 784
 785            if (is_string($key)) {
 786                $this->addFilter($key, $spec, $files);
 787                continue;
 788            }
 789
 790            if (is_int($key)) {
 791                if (is_string($spec)) {
 792                    $this->addFilter($spec, null, $files);
 793                    continue;
 794                }
 795
 796                if (is_array($spec)) {
 797                    if (!array_key_exists('filter', $spec)) {
 798                        continue;
 799                    }
 800
 801                    $filter = $spec['filter'];
 802                    unset($spec['filter']);
 803                    $this->addFilter($filter, $spec, $files);
 804                    continue;
 805                }
 806
 807                continue;
 808            }
 809        }
 810
 811        return $this;
 812    }
 813
 814    /**
 815     * Sets a filter for the class, erasing all previous set
 816     *
 817     * @param  string|array $filter Filter to set
 818     * @param  string|array $files     Files to limit this filter to
 819     * @return Zend_File_Transfer_Adapter
 820     */
 821    public function setFilters(array $filters, $files = null)
 822    {
 823        $this->clearFilters();
 824        return $this->addFilters($filters, $files);
 825    }
 826
 827    /**
 828     * Determine if a given filter has already been registered
 829     *
 830     * @param  string $name
 831     * @return bool
 832     */
 833    public function hasFilter($name)
 834    {
 835        return (false !== $this->_getFilterIdentifier($name));
 836    }
 837
 838    /**
 839     * Retrieve individual filter
 840     *
 841     * @param  string $name
 842     * @return Zend_Filter_Interface|null
 843     */
 844    public function getFilter($name)
 845    {
 846        if (false === ($identifier = $this->_getFilterIdentifier($name))) {
 847            return null;
 848        }
 849        return $this->_filters[$identifier];
 850    }
 851
 852    /**
 853     * Returns all set filters
 854     *
 855     * @param  string|array $files (Optional) Returns the filter for this files
 856     * @return array List of set filters
 857     * @throws Zend_File_Transfer_Exception When file not found
 858     */
 859    public function getFilters($files = null)
 860    {
 861        if ($files === null) {
 862            return $this->_filters;
 863        }
 864
 865        $files   = $this->_getFiles($files, true, true);
 866        $filters = array();
 867        foreach ($files as $file) {
 868            if (!empty($this->_files[$file]['filters'])) {
 869                $filters += $this->_files[$file]['filters'];
 870            }
 871        }
 872
 873        $filters = array_unique($filters);
 874        $result  = array();
 875        foreach ($filters as $filter) {
 876            $result[] = $this->_filters[$filter];
 877        }
 878
 879        return $result;
 880    }
 881
 882    /**
 883     * Remove an individual filter
 884     *
 885     * @param  string $name
 886     * @return Zend_File_Transfer_Adapter_Abstract
 887     */
 888    public function removeFilter($name)
 889    {
 890        if (false === ($key = $this->_getFilterIdentifier($name))) {
 891            return $this;
 892        }
 893
 894        unset($this->_filters[$key]);
 895        foreach (array_keys($this->_files) as $file) {
 896            if (empty($this->_files[$file]['filters'])) {
 897                continue;
 898            }
 899
 900            $index = array_search($key, $this->_files[$file]['filters']);
 901            if ($index === false) {
 902                continue;
 903            }
 904
 905            unset($this->_files[$file]['filters'][$index]);
 906        }
 907        return $this;
 908    }
 909
 910    /**
 911     * Remove all filters
 912     *
 913     * @return Zend_File_Transfer_Adapter_Abstract
 914     */
 915    public function clearFilters()
 916    {
 917        $this->_filters = array();
 918        foreach (array_keys($this->_files) as $file) {
 919            $this->_files[$file]['filters'] = array();
 920        }
 921        return $this;
 922    }
 923
 924    /**
 925     * Returns all set files
 926     *
 927     * @return array List of set files
 928     * @throws Zend_File_Transfer_Exception Not implemented
 929     */
 930    public function getFile()
 931    {
 932        #require_once 'Zend/File/Transfer/Exception.php';
 933        throw new Zend_File_Transfer_Exception('Method not implemented');
 934    }
 935
 936    /**
 937     * Retrieves the filename of transferred files.
 938     *
 939     * @param  string  $fileelement (Optional) Element to return the filename for
 940     * @param  boolean $path        (Optional) Should the path also be returned ?
 941     * @return string|array
 942     */
 943    public function getFileName($file = null, $path = true)
 944    {
 945        $files     = $this->_getFiles($file, true, true);
 946        $result    = array();
 947        $directory = "";
 948        foreach($files as $file) {
 949            if (empty($this->_files[$file]['name'])) {
 950                continue;
 951            }
 952
 953            if ($path === true) {
 954                $directory = $this->getDestination($file) . DIRECTORY_SEPARATOR;
 955            }
 956
 957            $result[$file] = $directory . $this->_files[$file]['name'];
 958        }
 959
 960        if (count($result) == 1) {
 961            return current($result);
 962        }
 963
 964        return $result;
 965    }
 966
 967    /**
 968     * Retrieve additional internal file informations for files
 969     *
 970     * @param  string $file (Optional) File to get informations for
 971     * @return array
 972     */
 973    public function getFileInfo($file = null)
 974    {
 975        return $this->_getFiles($file);
 976    }
 977
 978    /**
 979     * Adds one or more files
 980     *
 981     * @param  string|array $file      File to add
 982     * @param  string|array $validator Validators to use for this file, must be set before
 983     * @param  string|array $filter    Filters to use for this file, must be set before
 984     * @return Zend_File_Transfer_Adapter_Abstract
 985     * @throws Zend_File_Transfer_Exception Not implemented
 986     */
 987    public function addFile($file, $validator = null, $filter = null)
 988    {
 989        #require_once 'Zend/File/Transfer/Exception.php';
 990        throw new Zend_File_Transfer_Exception('Method not implemented');
 991    }
 992
 993    /**
 994     * Returns all set types
 995     *
 996     * @return array List of set types
 997     * @throws Zend_File_Transfer_Exception Not implemented
 998     */
 999    public function getType()
1000    {
1001        #require_once 'Zend/File/Transfer/Exception.php';
1002        throw new Zend_File_Transfer_Exception('Method not implemented');
1003    }
1004
1005    /**
1006     * Adds one or more type of files
1007     *
1008     * @param  string|array $type Type of files to add
1009     * @param  string|array $validator Validators to use for this file, must be set before
1010     * @param  string|array $filter    Filters to use for this file, must be set before
1011     * @return Zend_File_Transfer_Adapter_Abstract
1012     * @throws Zend_File_Transfer_Exception Not implemented
1013     */
1014    public function addType($type, $validator = null, $filter = null)
1015    {
1016        #require_once 'Zend/File/Transfer/Exception.php';
1017        throw new Zend_File_Transfer_Exception('Method not implemented');
1018    }
1019
1020    /**
1021     * Sets a new destination for the given files
1022     *
1023     * @deprecated Will be changed to be a filter!!!
1024     * @param  string       $destination New destination directory
1025     * @param  string|array $files       Files to set the new destination for
1026     * @return Zend_File_Transfer_Abstract
1027     * @throws Zend_File_Transfer_Exception when the given destination is not a directory or does not exist
1028     */
1029    public function setDestination($destination, $files = null)
1030    {
1031        $orig = $files;
1032        $destination = rtrim($destination, "/\\");
1033        if (!is_dir($destination)) {
1034            #require_once 'Zend/File/Transfer/Exception.php';
1035            throw new Zend_File_Transfer_Exception('The given destination is not a directory or does not exist');
1036        }
1037
1038        if (!is_writable($destination)) {
1039            #require_once 'Zend/File/Transfer/Exception.php';
1040            throw new Zend_File_Transfer_Exception('The given destination is not writeable');
1041        }
1042
1043        if ($files === null) {
1044            foreach ($this->_files as $file => $content) {
1045                $this->_files[$file]['destination'] = $destination;
1046            }
1047        } else {
1048            $files = $this->_getFiles($files, true, true);
1049            if (empty($files) and is_string($orig)) {
1050                $this->_files[$orig]['destination'] = $destination;
1051            }
1052
1053            foreach ($files as $file) {
1054                $this->_files[$file]['destination'] = $destination;
1055            }
1056        }
1057
1058        return $this;
1059    }
1060
1061    /**
1062     * Retrieve destination directory value
1063     *
1064     * @param  null|string|array $files
1065     * @return null|string|array
1066     */
1067    public function getDestination($files = null)
1068    {
1069        $orig  = $files;
1070        $files = $this->_getFiles($files, false, true);
1071        $destinations = array();
1072        if (empty($files) and is_string($orig)) {
1073            if (isset($this->_files[$orig]['destination'])) {
1074                $destinations[$orig] = $this->_files[$orig]['destination'];
1075            } else {
1076                #require_once 'Zend/File/Transfer/Exception.php';
1077                throw new Zend_File_Transfer_Exception(sprintf('The file transfer adapter can not find "%s"', $orig));
1078            }
1079        }
1080
1081        foreach ($files as $key => $content) {
1082            if (isset($this->_files[$key]['destination'])) {
1083                $destinations[$key] = $this->_files[$key]['destination'];
1084            } else {
1085                $tmpdir = $this->_getTmpDir();
1086                $this->setDestination($tmpdir, $key);
1087                $destinations[$key] = $tmpdir;
1088            }
1089        }
1090
1091        if (empty($destinations)) {
1092            $destinations = $this->_getTmpDir();
1093        } else if (count($destinations) == 1) {
1094            $destinations = current($destinations);
1095        }
1096
1097        return $destinations;
1098    }
1099
1100    /**
1101     * Set translator object for localization
1102     *
1103     * @param  Zend_Translate|null $translator
1104     * @return Zend_File_Transfer_Abstract
1105     */
1106    public function setTranslator($translator = null)
1107    {
1108        if (null === $translator) {
1109            $this->_translator = null;
1110        } elseif ($translator instanceof Zend_Translate_Adapter) {
1111            $this->_translator = $translator;
1112        } elseif ($translator instanceof Zend_Translate) {
1113            $this->_translator = $translator->getAdapter();
1114        } else {
1115            #require_once 'Zend/File/Transfer/Exception.php';
1116            throw new Zend_File_Transfer_Exception('Invalid translator specified');
1117        }
1118
1119        return $this;
1120    }
1121
1122    /**
1123     * Retrieve localization translator object
1124     *
1125     * @return Zend_Translate_Adapter|null
1126     */
1127    public function getTranslator()
1128    {
1129        if ($this->translatorIsDisabled()) {
1130            return null;
1131        }
1132
1133        return $this->_translator;
1134    }
1135
1136    /**
1137     * Indicate whether or not translation should be disabled
1138     *
1139     * @param  bool $flag
1140     * @return Zend_File_Transfer_Abstract
1141     */
1142    public function setDisableTranslator($flag)
1143    {
1144        $this->_translatorDisabled = (bool) $flag;
1145        return $this;
1146    }
1147
1148    /**
1149     * Is translation disabled?
1150     *
1151     * @return bool
1152     */
1153    public function translatorIsDisabled()
1154    {
1155        return $this->_translatorDisabled;
1156    }
1157
1158    /**
1159     * Returns the hash for a given file
1160     *
1161     * @param  string       $hash  Hash algorithm to use
1162     * @param  string|array $files Files to return the hash for
1163     * @return string|array Hashstring
1164     * @throws Zend_File_Transfer_Exception On unknown hash algorithm
1165     */
1166    public function getHash($hash = 'crc32', $files = null)
1167    {
1168        if (!in_array($hash, hash_algos())) {
1169            #require_once 'Zend/File/Transfer/Exception.php';
1170            throw new Zend_File_Transfer_Exception('Unknown hash algorithm');
1171        }
1172
1173        $files  = $this->_getFiles($files);
1174        $result = array();
1175        foreach($files as $key => $value) {
1176            if (file_exists($value['name'])) {
1177                $result[$key] = hash_file($hash, $value['name']);
1178            } else if (file_exists($value['tmp_name'])) {
1179                $result[$key] = hash_file($hash, $value['tmp_name']);
1180            } else if (empty($value['options']['ignoreNoFile'])) {
1181                #require_once 'Zend/File/Transfer/Exception.php';
1182                throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist");
1183            }
1184        }
1185
1186        if (count($result) == 1) {
1187            return current($result);
1188        }
1189
1190        return $result;
1191    }
1192
1193    /**
1194     * Returns the real filesize of the file
1195     *
1196     * @param string|array $files Files to get the filesize from
1197     * @throws Zend_File_Transfer_Exception When the file does not exist
1198     * @return string|array Filesize
1199     */
1200    public function getFileSize($files = null)
1201    {
1202        $files  = $this->_getFiles($files);
1203        $result = array();
1204        foreach($files as $key => $value) {
1205            if (file_exists($value['name']) || file_exists($value['tmp_name'])) {
1206                if ($value['options']['useByteString']) {
1207                    $result[$key] = self::_toByteString($value['size']);
1208                } else {
1209                    $result[$key] = $value['size'];
1210                }
1211            } else if (empty($value['options']['ignoreNoFile'])) {
1212                #require_once 'Zend/File/Transfer/Exception.php';
1213                throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist");
1214            } else {
1215                continue;
1216            }
1217        }
1218
1219        if (count($result) == 1) {
1220            return current($result);
1221        }
1222
1223        return $result;
1224    }
1225
1226    /**
1227     * Internal method to detect the size of a file
1228     *
1229     * @param  array $value File infos
1230     * @return string Filesize of given file
1231     */
1232    protected function _detectFileSize($value)
1233    {
1234        if (file_exists($value['name'])) {
1235            $result = sprintf("%u", @filesize($value['name']));
1236        } else if (file_exists($value['tmp_name'])) {
1237            $result = sprintf("%u", @filesize($value['tmp_name']));
1238        } else {
1239            return null;
1240        }
1241
1242        return $result;
1243    }
1244
1245    /**
1246     * Returns the real mimetype of the file
1247     * Uses fileinfo, when not available mime_magic and as last fallback a manual given mimetype
1248     *
1249     * @param string|array $files Files to get the mimetype from
1250     * @throws Zend_File_Transfer_Exception When the file does not exist
1251     * @return string|array MimeType
1252     */
1253    public function getMimeType($files = null)
1254    {
1255        $files  = $this->_getFiles($files);
1256        $result = array();
1257        foreach($files as $key => $value) {
1258            if (file_exists($value['name']) || file_exists($value['tmp_name'])) {
1259                $result[$key] = $value['type'];
1260            } else if (empty($value['options']['ignoreNoFile'])) {
1261                #require_once 'Zend/File/Transfer/Exception.php';
1262                throw new Zend_File_Transfer_Exception("The file '{$value['name']}' does not exist");
1263            } else {
1264                continue;
1265            }
1266        }
1267
1268        if (count($result) == 1) {
1269            return current($result);
1270        }
1271
1272        return $result;
1273    }
1274
1275    /**
1276     * Internal method to detect the mime type of a file
1277     *
1278     * @param  array $value File infos
1279     * @return string Mimetype of given file
1280     */
1281    protected function _detectMimeType($value)
1282    {
1283        if (file_exists($value['name'])) {
1284            $file = $value['name'];
1285        } else if (file_exists($value['tmp_name'])) {
1286            $file = $value['tmp_name'];
1287        } else {
1288            return null;
1289        }
1290
1291        if (class_exists('finfo', false)) {
1292            $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME;
1293            if (!empty($value['options']['magicFile'])) {
1294                $mime = @finfo_open($const, $value['options']['magicFile']);
1295            }
1296
1297            if (empty($mime)) {
1298                $mime = @finfo_open($const);
1299            }
1300
1301            if (!empty($mime)) {
1302                $result = finfo_file($mime, $file);
1303            }
1304
1305            unset($mime);
1306        }
1307
1308        if (empty($result) && (function_exists('mime_content_type')
1309            && ini_get('mime_magic.magicfile'))) {
1310            $result = mime_content_type($file);
1311        }
1312
1313        if (empty($result)) {
1314            $result = 'application/octet-stream';
1315        }
1316
1317        return $result;
1318    }
1319
1320    /**
1321     * Returns the formatted size
1322     *
1323     * @param  integer $size
1324     * @return string
1325     */
1326    protected static function _toByteString($size)
1327    {
1328        $sizes = array('B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB');
1329        for ($i=0; $size >= 1024 && $i < 9; $i++) {
1330            $size /= 1024;
1331        }
1332
1333        return round($size, 2) . $sizes[$i];
1334    }
1335
1336    /**
1337     * Internal function to filter all given files
1338     *
1339     * @param  string|array $files (Optional) Files to check
1340     * @return boolean False on error
1341     */
1342    protected function _filter($files = null)
1343    {
1344        $check           = $this->_getFiles($files);
1345        foreach ($check as $name => $content) {
1346            if (array_key_exists('filters', $content)) {
1347                foreach ($content['filters'] as $class) {
1348                    $filter = $this->_filters[$class];
1349                    try {
1350                        $result = $filter->filter($this->getFileName($name));
1351
1352                        $this->_files[$name]['destination'] = dirname($result);
1353                        $this->_files[$name]['name']        = basename($result);
1354                    } catch (Zend_Filter_Exception $e) {
1355                        $this->_messages += array($e->getMessage());
1356                    }
1357                }
1358            }
1359        }
1360
1361        if (count($this->_messages) > 0) {
1362            return false;
1363        }
1364
1365        return true;
1366    }
1367
1368    /**
1369     * Determine system TMP directory and detect if we have read access
1370     *
1371     * @return string
1372     * @throws Zend_File_Transfer_Exception if unable to determine directory
1373     */
1374    protected function _getTmpDir()
1375    {
1376        if (null === $this->_tmpDir) {
1377            $tmpdir = array();
1378            if (function_exists('sys_get_temp_dir')) {
1379                $tmpdir[] = sys_get_temp_dir();
1380            }
1381
1382            if (!empty($_ENV['TMP'])) {
1383                $tmpdir[] = realpath($_ENV['TMP']);
1384            }
1385
1386            if (!empty($_ENV['TMPDIR'])) {
1387                $tmpdir[] = realpath($_ENV['TMPDIR']);
1388            }
1389
1390            if (!empty($_ENV['TEMP'])) {
1391                $tmpdir[] = realpath($_ENV['TEMP']);
1392            }
1393
1394            $upload = ini_get('upload_tmp_dir');
1395            if ($upload) {
1396                $tmpdir[] = realpath($upload);
1397            }
1398
1399            foreach($tmpdir as $directory) {
1400                if ($this->_isPathWriteable($directory)) {
1401                    $this->_tmpDir = $directory;
1402                }
1403            }
1404
1405            if (empty($this->_tmpDir)) {
1406                // Attemp to detect by creating a temporary file
1407                $tempFile = tempnam(md5(uniqid(rand(), TRUE)), '');
1408                if ($tempFile) {
1409                    $this->_tmpDir = realpath(dirname($tempFile));
1410                    unlink($tempFile);
1411                } else {
1412                    #require_once 'Zend/File/Transfer/Exception.php';
1413                    throw new Zend_File_Transfer_Exception('Could not determine a temporary directory');
1414                }
1415            }
1416
1417            $this->_tmpDir = rtrim($this->_tmpDir, "/\\");
1418        }
1419        return $this->_tmpDir;
1420    }
1421
1422    /**
1423     * Tries to detect if we can read and write to the given path
1424     *
1425     * @param string $path
1426     */
1427    protected function _isPathWriteable($path)
1428    {
1429        $tempFile = rtrim($path, "/\\");
1430        $tempFile .= '/' . 'test.1';
1431
1432        $result = @file_put_contents($tempFile, 'TEST');
1433
1434        if ($result == false) {
1435            return false;
1436        }
1437
1438        $result = @unlink($tempFile);
1439
1440        if ($result == false) {
1441            return false;
1442        }
1443
1444        return true;
1445    }
1446
1447    /**
1448     * Returns found files based on internal file array and given files
1449     *
1450     * @param  string|array $files       (Optional) Files to return
1451     * @param  boolean      $names       (Optional) Returns only names on true, else complete info
1452     * @param  boolean      $noexception (Optional) Allows throwing an exception, otherwise returns an empty array
1453     * @return array Found files
1454     * @throws Zend_File_Transfer_Exception On false filename
1455     */
1456    protected function _getFiles($files, $names = false, $noexception = false)
1457    {
1458        $check = array();
1459
1460        if (is_string($files)) {
1461            $files = array($files);
1462        }
1463
1464        if (is_array($files)) {
1465            foreach ($files as $find) {
1466                $found = array();
1467                foreach ($this->_files as $file => $content) {
1468                    if (!isset($content['name'])) {
1469                        continue;
1470                    }
1471
1472                    if (($content['name'] === $find) && isset($content['multifiles'])) {
1473                        foreach ($content['multifiles'] as $multifile) {
1474                            $found[] = $multifile;
1475                        }
1476                        break;
1477                    }
1478
1479                    if ($file === $find) {
1480                        $found[] = $file;
1481                        break;
1482                    }
1483
1484                    if ($content['name'] === $find) {
1485                        $found[] = $file;
1486                        break;
1487                    }
1488                }
1489
1490                if (empty($found)) {
1491                    if ($noexception !== false) {
1492                        return array();
1493                    }
1494
1495                    #require_once 'Zend/File/Transfer/Exception.php';
1496                    throw new Zend_File_Transfer_Exception(sprintf('The file transfer adapter can not find "%s"', $find));
1497                }
1498
1499                foreach ($found as $checked) {
1500                    $check[$checked] = $this->_files[$checked];
1501                }
1502            }
1503        }
1504
1505        if ($files === null) {
1506            $check = $this->_files;
1507            $keys  = array_keys($check);
1508            foreach ($keys as $key) {
1509                if (isset($check[$key]['multifiles'])) {
1510                    unset($check[$key]);
1511                }
1512            }
1513        }
1514
1515        if ($names) {
1516            $check = array_keys($check);
1517        }
1518
1519        return $check;
1520    }
1521
1522    /**
1523     * Retrieve internal identifier for a named validator
1524     *
1525     * @param  string $name
1526     * @return string
1527     */
1528    protected function _getValidatorIdentifier($name)
1529    {
1530        if (array_key_exists($name, $this->_validators)) {
1531            return $name;
1532        }
1533
1534        foreach (array_keys($this->_validators) as $test) {
1535            if (preg_match('/' . preg_quote($name) . '$/i', $test)) {
1536                return $test;
1537            }
1538        }
1539
1540        return false;
1541    }
1542
1543    /**
1544     * Retrieve internal identifier for a named filter
1545     *
1546     * @param  string $name
1547     * @return string
1548     */
1549    protected function _getFilterIdentifier($name)
1550    {
1551        if (array_key_exists($name, $this->_filters)) {
1552            return $name;
1553        }
1554
1555        foreach (array_keys($this->_filters) as $test) {
1556            if (preg_match('/' . preg_quote($name) . '$/i', $test)) {
1557                return $test;
1558            }
1559        }
1560
1561        return false;
1562    }
1563}