1 /*
2  * Hunt - A high-level D Programming Language Web framework that encourages rapid development and clean, pragmatic design.
3  *
4  * Copyright (C) 2015-2019, HuntLabs
5  *
6  * Website: https://www.huntlabs.net/
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 module hunt.framework.file.UploadedFile;
13 
14 import hunt.framework.file.File;
15 import hunt.framework.Simplify;
16 
17 
18 class UploadedFile : File
19 {
20     private int _errorCode = 0;
21     private string _errorMessage = "Unknow error.";
22     private string _originalName;
23     private string _mimeType;
24 
25     /**
26      * Accepts the information of the uploaded file as provided by the PHP global $_FILES.
27      *
28      * The file object is only created when the uploaded file is valid (i.e. when the
29      * isValid() method returns true). Otherwise the only methods that could be called
30      * on an UploadedFile instance are:
31      *
32      *   * getClientOriginalName,
33      *   * getClientMimeType,
34      *   * isValid,
35      *   * getError.
36      *
37      * Calling any other method on an non-valid instance will cause an unpredictable result.
38      *
39      * @param string      $path         The full temporary path to the file
40      * @param string      $originalName The original file name of the uploaded file
41      * @param string|null $mimeType     The type of the file as provided by PHP; null defaults to application/octet-stream
42      * @param int|null    $error        The error constant of the upload (one of PHP's UPLOAD_ERR_XXX constants); null defaults to UPLOAD_ERR_OK
43      * @param bool        $test         Whether the test mode is active
44      *                                  Local files are used in test mode hence the code should not enforce HTTP uploads
45      *
46      * @throws FileException         If file_uploads is disabled
47      * @throws FileNotFoundException If the file does not exist
48      */
49     public this(string path, string originalName, string mimeType = null, int errorCode = 0)
50     {
51         this._originalName = this.getName(originalName);
52         this._mimeType = mimeType is null ? "application/octet-stream" : mimeType;
53         this._errorCode = errorCode;
54         
55         super(path, false);
56     }
57 
58     /**
59      * Returns the original file name.
60      *
61      * It is extracted from the request from which the file has been uploaded.
62      * Then it should not be considered as a safe value.
63      *
64      * @return string|null The original name
65      */
66     public string originalName()
67     {
68         return this._originalName;
69     }
70 
71     /**
72      * Returns the original file extension.
73      *
74      * It is extracted from the original file name that was uploaded.
75      * Then it should not be considered as a safe value.
76      *
77      * @return string The extension
78      */
79     override public string extension()
80     {
81         import std.string : lastIndexOf, replace;
82 
83         string extensionName;
84 
85         extensionName = this.path().replace("\\", "/");
86         extensionName = extensionName[lastIndexOf(extensionName, '/')..$];
87         
88         return extensionName;
89     }
90 
91     /**
92      * Returns the file mime type.
93      *
94      * The client mime type is extracted from the request from which the file
95      * was uploaded, so it should not be considered as a safe value.
96      *
97      * For a trusted mime type, use getMimeType() instead (which guesses the mime
98      * type based on the file content).
99      *
100      * @return string|null The mime type
101      *
102      * @see getMimeType()
103      */
104     override public string mimeType()
105     {
106         return this._mimeType;
107     }
108 
109     /**
110      * Returns the upload error.
111      *
112      * If the upload was successful, the constant UPLOAD_ERR_OK is returned.
113      * Otherwise one of the other UPLOAD_ERR_XXX constants is returned.
114      *
115      * @return int The upload error
116      */
117     public int getErrorCode()
118     {
119         return this._errorCode;
120     }
121 
122     /**
123      * Returns whether the file was uploaded successfully.
124      *
125      * @return bool True if the file has been uploaded with HTTP and no error occurred
126      */
127     public bool isValid()
128     {
129         return !this._errorCode;
130     }
131 
132     /**
133      * Returns the maximum size of an uploaded file as configured in php.ini.
134      *
135      * @return int The maximum size of an uploaded file in bytes
136      */
137     public static long maxSize()
138     {
139         return config().upload.maxSize;
140     }
141 
142     /**
143      * Store the uploaded file on a filesystem disk.
144      *
145      * @param  string  path
146      * @return false
147      */
148     public bool store(string path)
149     {
150         return this.move(path);
151     }
152 
153     /**
154      * Returns an informative upload error message.
155      *
156      * @return string The error message regarding the specified error code
157      */
158     public string getErrorMessage()
159     {
160         // static $errors = [
161         //     UPLOAD_ERR_INI_SIZE => 'The file "%s" exceeds your upload_max_filesize ini directive (limit is %d KiB).',
162         //     UPLOAD_ERR_FORM_SIZE => 'The file "%s" exceeds the upload limit defined in your form.',
163         //     UPLOAD_ERR_PARTIAL => 'The file "%s" was only partially uploaded.',
164         //     UPLOAD_ERR_NO_FILE => 'No file was uploaded.',
165         //     UPLOAD_ERR_CANT_WRITE => 'The file "%s" could not be written on disk.',
166         //     UPLOAD_ERR_NO_TMP_DIR => 'File could not be uploaded: missing temporary directory.',
167         //     UPLOAD_ERR_EXTENSION => 'File upload was stopped by a PHP extension.',
168         // ];
169 
170         // $errorCode = this._errorCode;
171         // $maxFilesize = UPLOAD_ERR_INI_SIZE === $errorCode ? self::getMaxFilesize() / 1024 : 0;
172         // $message = isset($errors[$errorCode]) ? $errors[$errorCode] : 'The file "%s" was not uploaded due to an unknown error.';
173         // return sprintf($message, this.getClientOriginalName(), $maxFilesize);
174 
175         return this._errorMessage;
176     }
177 }