Completed
Push — master ( e5db64...945d9a )
by Schlaefer
05:09 queued 28s
created

Uploader   C

Complexity

Total Complexity 54

Size/Duplication

Total Lines 335
Duplicated Lines 2.39 %

Coupling/Cohesion

Components 1
Dependencies 1

Importance

Changes 0
Metric Value
dl 8
loc 335
rs 6.4799
c 0
b 0
f 0
wmc 54
lcom 1
cbo 1

15 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 3 1
B __handleFileNameCallback() 8 23 7
A __handleUnique() 0 11 3
B processFile() 0 28 6
A setFile() 0 3 2
A _ext() 0 4 1
A _error() 0 3 1
B checkType() 0 26 7
A checkFile() 0 12 5
A checkSize() 0 16 6
A removeFile() 0 15 4
A hasUpload() 0 4 1
A hasErrors() 0 3 1
A showErrors() 0 7 2
B _multiArrayKeyExists() 0 15 7

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like Uploader often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use Uploader, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
  * Uploader class handles a single file to be uploaded to the file system
4
  *
5
  * @author: Nick Baker
6
  * @version: since 6.0.0
7
  * @link: http://www.webtechnick.com
8
  */
9
class Uploader {
10
11
  /**
12
    * File to upload.
13
    */
14
  var $file = array();
15
16
  /**
17
    * Global options
18
    * fileTypes to allow to upload
19
    */
20
  var $options = array();
21
22
  /**
23
    * errors holds any errors that occur as string values.
24
    * this can be access to debug the FileUploadComponent
25
    *
26
    * @var array
27
    * @access public
28
    */
29
  var $errors = array();
30
31
  /**
32
    * Definitions of errors that could occur during upload
33
    *
34
    * @author Jon Langevin
35
    * @var array
36
    */
37
  var $uploadErrors = array(
38
    UPLOAD_ERR_OK => 'There is no error, the file uploaded with success.',
39
    UPLOAD_ERR_INI_SIZE => 'The uploaded file exceeds the upload_max_filesize directive in php.ini.',
40
    UPLOAD_ERR_FORM_SIZE => 'The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form.',
41
    UPLOAD_ERR_PARTIAL => 'The uploaded file was only partially uploaded.',
42
    UPLOAD_ERR_NO_FILE => 'No file was uploaded.',
43
    UPLOAD_ERR_NO_TMP_DIR => 'Missing a temporary folder.', //Introduced in PHP 4.3.10 and PHP 5.0.3.
44
    UPLOAD_ERR_CANT_WRITE => 'Failed to write file to disk.', //Introduced in PHP 5.1.0.
45
    UPLOAD_ERR_EXTENSION => 'File upload stopped by extension.' //Introduced in PHP 5.2.0.
46
  );
47
48
  /**
49
    * Final file is set on move_uploaded_file success.
50
    * This is the file name of the final file that was uploaded
51
    * to the uploadDir directory
52
    *
53
    * @var string of final file name uploaded
54
    * @access public
55
    */
56
  var $finalFile = null;
57
58
  function __construct($options = array()){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
59
    $this->options = array_merge($this->options, $options);
60
  }
61
62
  /**
63
    * Preform requested callbacks on the filename.
64
    *
65
    * @var string chosen filename
66
    * @return string of resulting filename
67
    * @access private
68
    */
69
  function __handleFileNameCallback($fileName){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
70
    if($this->options['fileNameFunction']){
71
      if($this->options['fileModel']){
72
        $Model = ClassRegistry::init($this->options['fileModel']);
73
        if(method_exists($Model, $this->options['fileNameFunction'])){
74
          $fileName = $Model->{$this->options['fileNameFunction']}($fileName);
75
        }
76 View Code Duplication
        elseif(function_exists($this->options['fileNameFunction'])){
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
77
          $fileName = call_user_func($this->options['fileNameFunction'], $fileName);
78
        }
79
      }
80 View Code Duplication
      else {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
81
        if(function_exists($this->options['fileNameFunction'])){
82
          $fileName = call_user_func($this->options['fileNameFunction'], $fileName);
83
        }
84
      }
85
86
      if(!$fileName){
87
        $this->_error('No filename resulting after parsing. Function: ' . $this->options['fileNameFunction']);
88
      }
89
    }
90
    return $fileName;
91
  }
92
93
  /**
94
    * Preform requested target patch checks depending on the unique setting
95
    *
96
    * @var string chosen filename target_path
97
    * @return string of resulting target_path
98
    * @access private
99
    */
100
  function __handleUnique($target_path){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
101
    if($this->options['unique']){
102
      $temp_path = substr($target_path, 0, strlen($target_path) - strlen($this->_ext())); //temp path without the ext
103
      $i=1;
104
      while(file_exists($target_path)){
105
        $target_path = $temp_path . "-" . $i . $this->_ext();
106
        $i++;
107
      }
108
		}
109
    return $target_path;
110
  }
111
112
  /**
113
    * processFile will take a file, or use the current file given to it
114
    * and attempt to save the file to the file system.
115
    * processFile will check to make sure the file is there, and its type is allowed to be saved.
116
    *
117
    * @param file array of uploaded file (optional)
118
    * @return String | false String of finalFile name saved to the file system or false if unable to save to file system.
119
    * @access public
120
    */
121
  function processFile($file = null){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
122
    $this->setFile($file);
123
124
    //check if we have a file and if we allow the type, return false otherwise.
125
    if(!$this->checkFile() || !$this->checkType() || !$this->checkSize()){
126
      return false;
127
    }
128
129
    //make sure the file doesn't already exist, if it does, add an itteration to it
130
    $up_dir = $this->options['uploadDir'];
131
    $fileName = $this->__handleFileNameCallback($this->file['name']);
132
    //if callback returns false hault the upload
133
    if(!$fileName){
134
      return false;
135
    }
136
    $target_path = $up_dir . DS . $fileName;
137
    $target_path = $this->__handleUnique($target_path);
138
139
    //now move the file.
140
    if(move_uploaded_file($this->file['tmp_name'], $target_path)){
141
      $this->finalFile = basename($target_path);
142
      return $this->finalFile;
143
    }
144
    else{
145
      $this->_error('Unable to save temp file to file system.');
146
      return false;
147
    }
148
  }
149
150
  /**
151
    * setFile will set a this->file if given one.
152
    *
153
    * @param file array of uploaded file. (optional)
154
    * @return void
155
    */
156
  function setFile($file = null){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
157
    if($file) $this->file = $file;
158
  }
159
160
  /**
161
    * Returns the extension of the uploaded filename.
162
    *
163
    * @return string $extension A filename extension
164
    * @param file array of uploaded file (optional)
165
    * @access protected
166
    */
167
  function _ext($file = null){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
168
    $this->setFile($file);
169
    return strrchr($this->file['name'],".");
170
  }
171
172
  /**
173
  * Adds error messages to the component
174
  *
175
  * @param string $text String of error message to save
176
  * @return void
177
  * @access protected
178
  */
179
  function _error($text){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
180
    $this->errors[] = __($text);
181
  }
182
183
  /**
184
  * Checks if the uploaded type is allowed defined in the allowedTypes
185
  *
186
  * @return boolean if type is accepted
187
  * @param file array of uploaded file (optional)
188
  * @access public
189
  */
190
  function checkType($file = null){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
191
    $this->setFile($file);
192
    foreach($this->options['allowedTypes'] as $ext => $types){
193
      if(!is_string($ext)){
194
        $ext = $types;
195
      }
196
      if($ext == '*'){
197
        return true;
198
      }
199
200
      $ext = strtolower('.' . str_replace('.','', $ext));
201
      $file_ext = strtolower($this->_ext());
202
      if($file_ext == $ext){
203
        if(is_array($types) && !in_array($this->file['type'], $types)){
204
          $this->_error("{$this->file['type']} is not an allowed type.");
205
          return false;
206
        }
207
        else {
208
          return true;
209
        }
210
      }
211
    }
212
213
    $this->_error("Extension is not allowed.");
214
    return false;
215
  }
216
217
  /**
218
    * Checks if there is a file uploaded
219
    *
220
    * @return void
221
    * @access public
222
    * @param file array of uploaded file (optional)
223
    */
224
  function checkFile($file = null){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
225
    $this->setFile($file);
226
    if($this->hasUpload() && $this->file){
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->file of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
227
      if(isset($this->file['error']) && $this->file['error'] == UPLOAD_ERR_OK ) {
228
        return true;
229
      }
230
      else {
231
        $this->_error($this->uploadErrors[$this->file['error']]);
232
      }
233
    }
234
    return false;
235
  }
236
237
  /**
238
    * Checks if the file uploaded exceeds the maxFileSize setting (if there is onw)
239
    *
240
    * @return boolean
241
    * @access public
242
    * @param file array of uploaded file (optional)
243
    */
244
  function checkSize($file = null){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
245
    $this->setFile($file);
246
    if($this->hasUpload() && $this->file){
0 ignored issues
show
Bug Best Practice introduced by
The expression $this->file of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
247
      if(!$this->options['maxFileSize']){ //We don't want to test maxFileSize
248
        return true;
249
      }
250
      elseif($this->options['maxFileSize'] && $this->file['size'] < $this->options['maxFileSize']){
251
        return true;
252
      }
253
      else {
254
        // $this->_error("File exceeds {$this->options['maxFileSize']} byte limit.");
255
				$this->_error("File exceeds size limit.");
256
      }
257
    }
258
    return false;
259
  }
260
261
  /**
262
    * removeFile removes a specific file from the uploaded directory
263
    *
264
    * @param string $name A reference to the filename to delete from the uploadDirectory
265
    * @return boolean
266
    * @access public
267
    */
268
  function removeFile($name = null){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
269
    if(!$name || strpos($name, '://')){
0 ignored issues
show
Bug Best Practice introduced by
The expression $name of type string|null is loosely compared to false; this is ambiguous if the string can be empty. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
270
      return false;
271
    }
272
273
    $up_dir = $this->options['uploadDir'];
274
    $target_path = $up_dir . DS . $name;
275
276
    //delete main image -- $name
277
    if(@unlink($target_path)){
278
      return true;
279
    } else {
280
      return false;
281
    }
282
  }
283
284
  /**
285
    * hasUpload
286
    *
287
    * @return boolean true | false depending if a file was actually uploaded.
288
    * @param file array of uploaded file (optional)
289
    */
290
  function hasUpload($file = null){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
291
    $this->setFile($file);
292
    return ($this->_multiArrayKeyExists("tmp_name", $this->file));
293
  }
294
295
  /**
296
    * @return boolean true if errors were detected.
297
    */
298
  function hasErrors(){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
299
    return count($this->errors);
300
  }
301
302
  /**
303
    * showErrors itterates through the errors array
304
    * and returns a concatinated string of errors sepearated by
305
    * the $sep
306
    *
307
    * @param string $sep A seperated defaults to <br />
308
    * @return string
309
    * @access public
310
    */
311
  function showErrors($sep = " "){
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
312
    $retval = "";
313
    foreach($this->errors as $error){
314
      $retval .= "$error $sep";
315
    }
316
    return $retval;
317
  }
318
319
  /**
320
    * Searches through the $haystack for a $key.
321
    *
322
    * @param string $needle String of key to search for in $haystack
323
    * @param array $haystack Array of which to search for $needle
324
    * @return boolean true if given key is in an array
325
    * @access protected
326
    */
327
  function _multiArrayKeyExists($needle, $haystack) {
0 ignored issues
show
Best Practice introduced by
It is generally recommended to explicitly declare the visibility for methods.

Adding explicit visibility (private, protected, or public) is generally recommend to communicate to other developers how, and from where this method is intended to be used.

Loading history...
328
    if(is_array($haystack)){
329
      foreach ($haystack as $key=>$value) {
330
        if ($needle===$key && $value) {
331
          return true;
332
        }
333
        if (is_array($value)) {
334
          if($this->_multiArrayKeyExists($needle, $value)){
335
            return true;
336
          }
337
        }
338
      }
339
    }
340
    return false;
341
  }
342
343
}
344
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...