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 classes like CKFinder_Connector_CommandHandler_Thumbnail 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 CKFinder_Connector_CommandHandler_Thumbnail, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
28 | class CKFinder_Connector_CommandHandler_Thumbnail extends CKFinder_Connector_CommandHandler_CommandHandlerBase |
||
29 | { |
||
30 | /** |
||
31 | * Command name |
||
32 | * |
||
33 | * @access private |
||
34 | * @var string |
||
35 | */ |
||
36 | var $command = "Thumbnail"; |
||
37 | |||
38 | /** |
||
39 | * Send response |
||
40 | * @access public |
||
41 | * |
||
42 | */ |
||
43 | function sendResponse() |
||
44 | { |
||
45 | if (!function_exists('ob_list_handlers') || ob_list_handlers()) { |
||
46 | @ob_end_clean(); |
||
47 | } |
||
48 | header("Content-Encoding: none"); |
||
49 | |||
50 | $this->checkConnector(); |
||
51 | $this->checkRequest(); |
||
52 | |||
53 | $_config =& CKFinder_Connector_Core_Factory::getInstance("Core_Config"); |
||
54 | |||
55 | $_thumbnails = $_config->getThumbnailsConfig(); |
||
56 | if (!$_thumbnails->getIsEnabled()) { |
||
57 | $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_THUMBNAILS_DISABLED); |
||
58 | } |
||
59 | |||
60 | if (!$this->_currentFolder->checkAcl(CKFINDER_CONNECTOR_ACL_FILE_VIEW)) { |
||
61 | $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_UNAUTHORIZED); |
||
62 | } |
||
63 | |||
64 | if (!isset($_GET["FileName"])) { |
||
65 | $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST); |
||
66 | } |
||
67 | |||
68 | $fileName = CKFinder_Connector_Utils_FileSystem::convertToFilesystemEncoding($_GET["FileName"]); |
||
69 | $_resourceTypeInfo = $this->_currentFolder->getResourceTypeConfig(); |
||
70 | |||
71 | if (!CKFinder_Connector_Utils_FileSystem::checkFileName($fileName)) { |
||
72 | $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_INVALID_REQUEST); |
||
73 | } |
||
74 | $sourceFilePath = CKFinder_Connector_Utils_FileSystem::combinePaths($this->_currentFolder->getServerPath(), $fileName); |
||
75 | |||
76 | if ($_resourceTypeInfo->checkIsHiddenFile($fileName) || !file_exists($sourceFilePath)) { |
||
77 | $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_FILE_NOT_FOUND); |
||
78 | } |
||
79 | |||
80 | $thumbFilePath = CKFinder_Connector_Utils_FileSystem::combinePaths($this->_currentFolder->getThumbsServerPath(), $fileName); |
||
81 | |||
82 | // If the thumbnail file doesn't exists, create it now. |
||
83 | if (!file_exists($thumbFilePath)) { |
||
84 | if(!$this->createThumb($sourceFilePath, $thumbFilePath, $_thumbnails->getMaxWidth(), $_thumbnails->getMaxHeight(), $_thumbnails->getQuality(), true, $_thumbnails->getBmpSupported())) { |
||
85 | $this->_errorHandler->throwError(CKFINDER_CONNECTOR_ERROR_ACCESS_DENIED); |
||
86 | } |
||
87 | } |
||
88 | |||
89 | $size = filesize($thumbFilePath); |
||
90 | $sourceImageAttr = getimagesize($thumbFilePath); |
||
91 | $mime = $sourceImageAttr["mime"]; |
||
92 | |||
93 | $rtime = isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])?strtotime($_SERVER["HTTP_IF_MODIFIED_SINCE"]):0; |
||
94 | $mtime = filemtime($thumbFilePath); |
||
95 | $etag = dechex($mtime) . "-" . dechex($size); |
||
96 | |||
97 | $is304 = false; |
||
98 | |||
99 | if (isset($_SERVER["HTTP_IF_NONE_MATCH"]) && $_SERVER["HTTP_IF_NONE_MATCH"] === $etag) { |
||
100 | $is304 = true; |
||
101 | } |
||
102 | else if($rtime == $mtime) { |
||
103 | $is304 = true; |
||
104 | } |
||
105 | |||
106 | if ($is304) { |
||
107 | header("HTTP/1.0 304 Not Modified"); |
||
108 | exit(); |
||
109 | } |
||
110 | |||
111 | //header("Cache-Control: cache, must-revalidate"); |
||
112 | //header("Pragma: public"); |
||
113 | //header("Expires: 0"); |
||
114 | header('Cache-control: public'); |
||
115 | header('Etag: ' . $etag); |
||
116 | header("Content-type: " . $mime . "; name=\"" . CKFinder_Connector_Utils_Misc::mbBasename($thumbFilePath) . "\""); |
||
117 | header("Last-Modified: ".gmdate('D, d M Y H:i:s', $mtime) . " GMT"); |
||
118 | //header("Content-type: application/octet-stream; name=\"{$file}\""); |
||
119 | //header("Content-Disposition: attachment; filename=\"{$file}\""); |
||
120 | header("Content-Length: ".$size); |
||
121 | readfile($thumbFilePath); |
||
122 | exit; |
||
123 | } |
||
124 | |||
125 | /** |
||
126 | * Create thumbnail |
||
127 | * |
||
128 | * @param string $sourceFile |
||
129 | * @param string $targetFile |
||
130 | * @param int $maxWidth |
||
131 | * @param int $maxHeight |
||
132 | * @param boolean $preserverAspectRatio |
||
133 | * @param boolean $bmpSupported |
||
134 | * @return boolean |
||
135 | * @static |
||
136 | * @access public |
||
137 | */ |
||
138 | function createThumb($sourceFile, $targetFile, $maxWidth, $maxHeight, $quality, $preserverAspectRatio, $bmpSupported = false) |
||
139 | { |
||
140 | $sourceImageAttr = @getimagesize($sourceFile); |
||
141 | if ($sourceImageAttr === false) { |
||
142 | return false; |
||
143 | } |
||
144 | $sourceImageWidth = isset($sourceImageAttr[0]) ? $sourceImageAttr[0] : 0; |
||
145 | $sourceImageHeight = isset($sourceImageAttr[1]) ? $sourceImageAttr[1] : 0; |
||
146 | $sourceImageMime = isset($sourceImageAttr["mime"]) ? $sourceImageAttr["mime"] : ""; |
||
147 | $sourceImageBits = isset($sourceImageAttr["bits"]) ? $sourceImageAttr["bits"] : 8; |
||
148 | $sourceImageChannels = isset($sourceImageAttr["channels"]) ? $sourceImageAttr["channels"] : 3; |
||
149 | |||
150 | if (!$sourceImageWidth || !$sourceImageHeight || !$sourceImageMime) { |
||
151 | return false; |
||
152 | } |
||
153 | |||
154 | $iFinalWidth = $maxWidth == 0 ? $sourceImageWidth : $maxWidth; |
||
155 | $iFinalHeight = $maxHeight == 0 ? $sourceImageHeight : $maxHeight; |
||
156 | |||
157 | if ($sourceImageWidth <= $iFinalWidth && $sourceImageHeight <= $iFinalHeight) { |
||
158 | if ($sourceFile != $targetFile) { |
||
159 | copy($sourceFile, $targetFile); |
||
160 | } |
||
161 | return true; |
||
162 | } |
||
163 | |||
164 | if ($preserverAspectRatio) |
||
165 | { |
||
166 | // Gets the best size for aspect ratio resampling |
||
167 | $oSize = CKFinder_Connector_CommandHandler_Thumbnail::GetAspectRatioSize($iFinalWidth, $iFinalHeight, $sourceImageWidth, $sourceImageHeight ); |
||
168 | } |
||
169 | else { |
||
170 | $oSize = array('Width' => $iFinalWidth, 'Height' => $iFinalHeight); |
||
171 | } |
||
172 | |||
173 | CKFinder_Connector_Utils_Misc::setMemoryForImage($sourceImageWidth, $sourceImageHeight, $sourceImageBits, $sourceImageChannels); |
||
174 | |||
175 | switch ($sourceImageAttr['mime']) |
||
176 | { |
||
177 | case 'image/gif': |
||
178 | { |
||
179 | if (@imagetypes() & IMG_GIF) { |
||
180 | $oImage = @imagecreatefromgif($sourceFile); |
||
181 | } else { |
||
182 | $ermsg = 'GIF images are not supported'; |
||
183 | } |
||
184 | } |
||
185 | break; |
||
186 | case 'image/jpeg': |
||
187 | { |
||
188 | if (@imagetypes() & IMG_JPG) { |
||
189 | $oImage = @imagecreatefromjpeg($sourceFile) ; |
||
190 | } else { |
||
191 | $ermsg = 'JPEG images are not supported'; |
||
192 | } |
||
193 | } |
||
194 | break; |
||
195 | case 'image/png': |
||
196 | { |
||
197 | if (@imagetypes() & IMG_PNG) { |
||
198 | $oImage = @imagecreatefrompng($sourceFile) ; |
||
199 | } else { |
||
200 | $ermsg = 'PNG images are not supported'; |
||
201 | } |
||
202 | } |
||
203 | break; |
||
204 | case 'image/wbmp': |
||
205 | { |
||
206 | if (@imagetypes() & IMG_WBMP) { |
||
207 | $oImage = @imagecreatefromwbmp($sourceFile); |
||
208 | } else { |
||
209 | $ermsg = 'WBMP images are not supported'; |
||
210 | } |
||
211 | } |
||
212 | break; |
||
213 | case 'image/bmp': |
||
214 | { |
||
215 | /* |
||
216 | * This is sad that PHP doesn't support bitmaps. |
||
217 | * Anyway, we will use our custom function at least to display thumbnails. |
||
218 | * We'll not resize images this way (if $sourceFile === $targetFile), |
||
219 | * because user defined imagecreatefrombmp and imagecreatebmp are horribly slow |
||
220 | */ |
||
221 | if ($bmpSupported && (@imagetypes() & IMG_JPG) && $sourceFile != $targetFile) { |
||
222 | $oImage = CKFinder_Connector_Utils_Misc::imageCreateFromBmp($sourceFile); |
||
223 | } else { |
||
224 | $ermsg = 'BMP/JPG images are not supported'; |
||
225 | } |
||
226 | } |
||
227 | break; |
||
228 | default: |
||
229 | $ermsg = $sourceImageAttr['mime'].' images are not supported'; |
||
230 | break; |
||
231 | } |
||
232 | |||
233 | if (isset($ermsg) || false === $oImage) { |
||
234 | return false; |
||
235 | } |
||
236 | |||
237 | |||
238 | $oThumbImage = imagecreatetruecolor($oSize["Width"], $oSize["Height"]); |
||
239 | //imagecopyresampled($oThumbImage, $oImage, 0, 0, 0, 0, $oSize["Width"], $oSize["Height"], $sourceImageWidth, $sourceImageHeight); |
||
240 | CKFinder_Connector_Utils_Misc::fastImageCopyResampled($oThumbImage, $oImage, 0, 0, 0, 0, $oSize["Width"], $oSize["Height"], $sourceImageWidth, $sourceImageHeight, (int)max(floor($quality/20), 1)); |
||
241 | |||
242 | switch ($sourceImageAttr['mime']) |
||
243 | { |
||
244 | case 'image/gif': |
||
245 | imagegif($oThumbImage, $targetFile); |
||
246 | break; |
||
247 | case 'image/jpeg': |
||
248 | case 'image/bmp': |
||
249 | imagejpeg($oThumbImage, $targetFile, $quality); |
||
250 | break; |
||
251 | case 'image/png': |
||
252 | imagepng($oThumbImage, $targetFile); |
||
253 | break; |
||
254 | case 'image/wbmp': |
||
255 | imagewbmp($oThumbImage, $targetFile); |
||
256 | break; |
||
257 | } |
||
258 | |||
259 | $_config =& CKFinder_Connector_Core_Factory::getInstance("Core_Config"); |
||
260 | if (file_exists($targetFile) && ($perms = $_config->getChmodFiles())) { |
||
261 | $oldUmask = umask(0); |
||
262 | chmod($targetFile, $perms); |
||
263 | umask($oldUmask); |
||
264 | } |
||
265 | |||
266 | imageDestroy($oImage); |
||
267 | imageDestroy($oThumbImage); |
||
268 | |||
269 | return true; |
||
270 | } |
||
271 | |||
272 | |||
273 | |||
274 | /** |
||
275 | * Return aspect ratio size, returns associative array: |
||
276 | * <pre> |
||
277 | * Array |
||
278 | * ( |
||
279 | * [Width] => 80 |
||
280 | * [Heigth] => 120 |
||
281 | * ) |
||
282 | * </pre> |
||
283 | * |
||
284 | * @param int $maxWidth |
||
285 | * @param int $maxHeight |
||
286 | * @param int $actualWidth |
||
287 | * @param int $actualHeight |
||
288 | * @return array |
||
289 | * @static |
||
290 | * @access public |
||
291 | */ |
||
292 | function getAspectRatioSize($maxWidth, $maxHeight, $actualWidth, $actualHeight) |
||
293 | { |
||
294 | $oSize = array("Width"=>$maxWidth, "Height"=>$maxHeight); |
||
295 | |||
296 | // Calculates the X and Y resize factors |
||
297 | $iFactorX = (float)$maxWidth / (float)$actualWidth; |
||
298 | $iFactorY = (float)$maxHeight / (float)$actualHeight; |
||
299 | |||
300 | // If some dimension have to be scaled |
||
301 | if ($iFactorX != 1 || $iFactorY != 1) |
||
302 | { |
||
303 | // Uses the lower Factor to scale the oposite size |
||
304 | if ($iFactorX < $iFactorY) { |
||
305 | $oSize["Height"] = (int)round($actualHeight * $iFactorX); |
||
306 | } |
||
307 | else if ($iFactorX > $iFactorY) { |
||
308 | $oSize["Width"] = (int)round($actualWidth * $iFactorY); |
||
309 | } |
||
310 | } |
||
311 | |||
312 | if ($oSize["Height"] <= 0) { |
||
313 | $oSize["Height"] = 1; |
||
314 | } |
||
315 | if ($oSize["Width"] <= 0) { |
||
316 | $oSize["Width"] = 1; |
||
317 | } |
||
318 | |||
319 | // Returns the Size |
||
320 | return $oSize; |
||
321 | } |
||
322 | } |
||
323 |