1<?php
2/**
3 * Zend Framework (http://framework.zend.com/)
4 *
5 * @link      http://github.com/zendframework/zf2 for the canonical source repository
6 * @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
7 * @license   http://framework.zend.com/license/new-bsd New BSD License
8 */
9
10namespace Zend\Validator\File;
11
12use Zend\Validator\AbstractValidator;
13use Zend\Validator\Exception;
14
15/**
16 * Validator for the maximum size of a file up to a max of 2GB
17 */
18class UploadFile extends AbstractValidator
19{
20    /**
21     * @const string Error constants
22     */
23    const INI_SIZE       = 'fileUploadFileErrorIniSize';
24    const FORM_SIZE      = 'fileUploadFileErrorFormSize';
25    const PARTIAL        = 'fileUploadFileErrorPartial';
26    const NO_FILE        = 'fileUploadFileErrorNoFile';
27    const NO_TMP_DIR     = 'fileUploadFileErrorNoTmpDir';
28    const CANT_WRITE     = 'fileUploadFileErrorCantWrite';
29    const EXTENSION      = 'fileUploadFileErrorExtension';
30    const ATTACK         = 'fileUploadFileErrorAttack';
31    const FILE_NOT_FOUND = 'fileUploadFileErrorFileNotFound';
32    const UNKNOWN        = 'fileUploadFileErrorUnknown';
33
34    /**
35     * @var array Error message templates
36     */
37    protected $messageTemplates = array(
38        self::INI_SIZE       => "File exceeds the defined ini size",
39        self::FORM_SIZE      => "File exceeds the defined form size",
40        self::PARTIAL        => "File was only partially uploaded",
41        self::NO_FILE        => "File was not uploaded",
42        self::NO_TMP_DIR     => "No temporary directory was found for file",
43        self::CANT_WRITE     => "File can't be written",
44        self::EXTENSION      => "A PHP extension returned an error while uploading the file",
45        self::ATTACK         => "File was illegally uploaded. This could be a possible attack",
46        self::FILE_NOT_FOUND => "File was not found",
47        self::UNKNOWN        => "Unknown error while uploading file",
48    );
49
50    /**
51     * Returns true if and only if the file was uploaded without errors
52     *
53     * @param  string $value File to check for upload errors
54     * @return bool
55     * @throws Exception\InvalidArgumentException
56     */
57    public function isValid($value)
58    {
59        if (is_array($value)) {
60            if (!isset($value['tmp_name']) || !isset($value['name']) || !isset($value['error'])) {
61                throw new Exception\InvalidArgumentException(
62                    'Value array must be in $_FILES format'
63                );
64            }
65            $file     = $value['tmp_name'];
66            $filename = $value['name'];
67            $error    = $value['error'];
68        } else {
69            $file     = $value;
70            $filename = basename($file);
71            $error    = 0;
72        }
73        $this->setValue($filename);
74
75        switch ($error) {
76            case UPLOAD_ERR_OK:
77                if (empty($file) || false === is_file($file)) {
78                    $this->error(self::FILE_NOT_FOUND);
79                } elseif (! is_uploaded_file($file)) {
80                    $this->error(self::ATTACK);
81                }
82                break;
83
84            case UPLOAD_ERR_INI_SIZE:
85                $this->error(self::INI_SIZE);
86                break;
87
88            case UPLOAD_ERR_FORM_SIZE:
89                $this->error(self::FORM_SIZE);
90                break;
91
92            case UPLOAD_ERR_PARTIAL:
93                $this->error(self::PARTIAL);
94                break;
95
96            case UPLOAD_ERR_NO_FILE:
97                $this->error(self::NO_FILE);
98                break;
99
100            case UPLOAD_ERR_NO_TMP_DIR:
101                $this->error(self::NO_TMP_DIR);
102                break;
103
104            case UPLOAD_ERR_CANT_WRITE:
105                $this->error(self::CANT_WRITE);
106                break;
107
108            case UPLOAD_ERR_EXTENSION:
109                $this->error(self::EXTENSION);
110                break;
111
112            default:
113                $this->error(self::UNKNOWN);
114                break;
115        }
116
117        if (count($this->getMessages()) > 0) {
118            return false;
119        }
120
121        return true;
122    }
123}
124