CWIS Developer Documentation

- Home
- Main Page
- Namespaces
- Classes
- Files

- File List
- File Members

SPTImage.php
Go to the documentation of this file.
1 <?PHP
2 #
3 # FILE: SPTImage.php
4 #
5 # METHODS PROVIDED:
6 # SPTImage($ImageIdOrFileNameOrImageObj,
7 # $MaxPreviewWidth = NULL, $MaxPreviewHeight = NULL,
8 # $MaxThumbnailWidth = NULL, $MaxThumbnailHeight = NULL)
9 # - object constructor
10 # Delete()
11 # - delete image and associated files and data
12 # AltText($NewValue = NULL)
13 # - get/set alt text attribute
14 # Id()
15 # Url()
16 # PreviewUrl()
17 # ThumbnailUrl()
18 # Format()
19 # Height()
20 # Width()
21 # PreviewHeight()
22 # PreviewWidth()
23 # ThumbnailHeight()
24 # ThumbnailWidth()
25 # - get attributes
26 #
27 # AUTHOR: Edward Almasy
28 #
29 # Part of CWIS
30 # Copyright 2002-2011 Internet Scout Project
31 # http://scout.wisc.edu
32 #
33
34 class SPTImage {
35
36 # ---- PUBLIC INTERFACE --------------------------------------------------
37
39 const IMAGE_PATH = "ImageStorage/";
41 const PREVIEW_PATH = "ImageStorage/Previews/";
43 const THUMBNAIL_PATH = "ImageStorage/Thumbnails/";
44
45 # object constructor
46 function SPTImage($ImageIdOrFileNameOrImageObj,
47 $MaxWidth = NULL, $MaxHeight = NULL,
48 $MaxPreviewWidth = NULL, $MaxPreviewHeight = NULL,
49 $MaxThumbnailWidth = NULL, $MaxThumbnailHeight = NULL)
50 {
51 # clear error status (0 = AI_OKAY)
52 $this->ErrorStatus = 0;
53
54 # trigger the Image class file to be autoloaded since some parts of this
55 # class (SPTImage) use constants defined in it but don't construct Image
56 # objects
57 new Image(NULL);
58
59 # create and save a database handle for our use
60 $this->DB = new Database();
61
62 # if image object was passed in
63 if (is_object($ImageIdOrFileNameOrImageObj)
64 && method_exists($ImageIdOrFileNameOrImageObj, "SPTImage"))
65 {
66 # create copy of image passed in
67 $this->CreateCopyOfImage($ImageIdOrFileNameOrImageObj);
68 }
69 # else if image ID was passed in
70 elseif (($ImageIdOrFileNameOrImageObj > 0)
71 && preg_match("/[0-9]+/", $ImageIdOrFileNameOrImageObj))
72 {
73 # load info on existing image
74 $this->LoadImageInfo($ImageIdOrFileNameOrImageObj);
75 }
76 # else assume that value passed in is file name
77 else
78 {
79 # create new image from named file
80 $this->CreateNewImage($ImageIdOrFileNameOrImageObj,
81 $MaxWidth, $MaxHeight,
82 $MaxPreviewWidth, $MaxPreviewHeight,
83 $MaxThumbnailWidth, $MaxThumbnailHeight);
84 }
85 }
86
87 # get attributes
88 function Id() { return $this->Id; }
89 function Url() { return $this->FileName; }
90 function PreviewUrl() { return $this->PreviewFileName; }
91 function ThumbnailUrl() { return $this->ThumbnailFileName; }
92 function Format() { return $this->Format; }
93 function Height() { return $this->Height; }
94 function Width() { return $this->Width; }
95 function PreviewHeight() { return $this->PreviewHeight; }
96 function PreviewWidth() { return $this->PreviewWidth; }
97 function ThumbnailHeight() { return $this->ThumbnailHeight; }
98 function ThumbnailWidth() { return $this->ThumbnailWidth; }
99 function ImageStorageDirectory() { return self::IMAGE_PATH; }
100 function PreviewStorageDirectory() { return self::PREVIEW_PATH; }
101 function ThumbnailStorageDirectory() { return self::THUMBNAIL_PATH; }
102 function GetLink() { return $this->FileName; }
103
104 # get/set attributes
105 function AltText($NewValue = NULL)
106 {
107 # if new value supplied and new value differs from existing value
108 if (($NewValue !== NULL) && ($NewValue != $this->AltText))
109 {
110 # save new value to database
111 $this->DB->Query("UPDATE Images SET"
112 ." AltText = '".addslashes($NewValue)."'"
113 ." WHERE ImageId = ".$this->Id);
114
115 # save new value locally
116 $this->AltText = $NewValue;
117 }
118
119 # return attribute value to caller
120 return $this->AltText;
121 }
122
123 # delete image and associated files and data
124 function Delete()
125 {
126 # delete base image file
127 if (file_exists($this->FileName)) { unlink($this->FileName); }
128
129 # delete preview image file
130 if (file_exists($this->PreviewFileName)) { unlink($this->PreviewFileName); }
131
132 # delete thumbnail image file
133 if (file_exists($this->ThumbnailFileName)) { unlink($this->ThumbnailFileName); }
134
135 # delete image info record in database
136 $this->DB->Query("DELETE FROM Images WHERE ImageId = ".$this->Id);
137 }
138
139 # return error status set by the constructor
140 function Status()
141 {
142 return $this->ErrorStatus;
143 }
144
145 # check to make sure image storage directories are available
146 # (returns array of error codes or NULL if no errors found)
147 static function CheckDirectories()
148 {
149 # determine paths
150 $ImagePath = self::IMAGE_PATH;
151 $PreviewPath = self::PREVIEW_PATH;
152 $ThumbnailPath = self::THUMBNAIL_PATH;
153
154 # assume everything will be okay
155 $ErrorsFound = NULL;
156
157 # check base image directory
158 if (!is_dir($ImagePath) || !is_writable($ImagePath))
159 {
160 if (!is_dir($ImagePath))
161 {
162 @mkdir($ImagePath, 0755);
163 }
164 else
165 {
166 @chmod($ImagePath, 0755);
167 }
168 if (!is_dir($ImagePath))
169 {
170 $ErrorsFound[] = "Image Storage Directory Not Found";
171 }
172 elseif (!is_writable($ImagePath))
173 {
174 $ErrorsFound[] = "Image Storage Directory Not Writable";
175 }
176 }
177
178 # check preview directory
179 if (!is_dir($PreviewPath) || !is_writable($PreviewPath))
180 {
181 if (!is_dir($PreviewPath))
182 {
183 @mkdir($PreviewPath, 0755);
184 }
185 else
186 {
187 @chmod($PreviewPath, 0755);
188 }
189 if (!is_dir($PreviewPath))
190 {
191 $ErrorsFound[] = "Preview Storage Directory Not Found";
192 }
193 elseif (!is_writable($PreviewPath))
194 {
195 $ErrorsFound[] = "Preview Storage Directory Not Writable";
196 }
197 }
198
199 # check thumbnail directory
200 if (!is_dir($ThumbnailPath) || !is_writable($ThumbnailPath))
201 {
202 if (!is_dir($ThumbnailPath))
203 {
204 @mkdir($ThumbnailPath, 0755);
205 }
206 else
207 {
208 @chmod($ThumbnailPath, 0755);
209 }
210 if (!is_dir($ThumbnailPath))
211 {
212 $ErrorsFound[] = "Thumbnail Storage Directory Not Found";
213 }
214 elseif (!is_writable($ThumbnailPath))
215 {
216 $ErrorsFound[] = "Thumbnail Storage Directory Not Writable";
217 }
218 }
219
220 # return any errors found to caller
221 return $ErrorsFound;
222 }
223
224 public function Resize($MaxWidth, $MaxHeight,
225 $MaxPreviewWidth, $MaxPreviewHeight,
226 $MaxThumbnailWidth, $MaxThumbnailHeight)
227 {
228 $SrcImage = new Image($this->FileName);
229
230 # scale the original image if necessary
231 $MaxWidth = min($MaxWidth, $SrcImage->XSize());
232 $MaxHeight = min($MaxHeight, $SrcImage->YSize());
233 $SrcImage->ScaleTo($MaxWidth, $MaxHeight, TRUE);
234
235 # save and reload image info
236 $SrcImage->SaveAs($this->FileName);
237 $SrcImage = new Image($this->FileName);
238
239 # retrieve image width and height
240 $this->Height = $SrcImage->YSize();
241 $this->Width = $SrcImage->XSize();
242
243 # generate preview image and calculate width and height
244 $MaxPreviewWidth = min($MaxPreviewWidth, $this->Width);
245 $MaxPreviewHeight = min($MaxPreviewHeight, $this->Height);
246 $SrcImage->ScaleTo($MaxPreviewWidth, $MaxPreviewHeight, TRUE);
247 $SrcImage->SaveAs($this->PreviewFileName, IMGTYPE_JPEG);
248 if (($this->Width * $MaxPreviewHeight)
249 > ($this->Height * $MaxPreviewWidth))
250 {
251 $this->PreviewWidth = $MaxPreviewWidth;
252 $this->PreviewHeight =
253 ($MaxPreviewWidth * $SrcImage->YSize()) / $SrcImage->XSize();
254 }
255 else
256 {
257 $this->PreviewWidth =
258 ($MaxPreviewHeight * $SrcImage->XSize()) / $SrcImage->YSize();
259 $this->PreviewHeight = $MaxPreviewHeight;
260 }
261
262 # generate thumbnail image and calculate width and height
263 $MaxThumbnailWidth = min($MaxThumbnailWidth, $this->Width);
264 $MaxThumbnailHeight = min($MaxThumbnailHeight, $this->Height);
265 $SrcImage->ScaleTo($MaxThumbnailWidth, $MaxThumbnailHeight, TRUE);
266 $SrcImage->SaveAs($this->ThumbnailFileName, IMGTYPE_JPEG);
267 if (($this->Width * $MaxThumbnailHeight)
268 > ($this->Height * $MaxThumbnailWidth))
269 {
270 $this->ThumbnailWidth = $MaxThumbnailWidth;
271 $this->ThumbnailHeight =
272 ($MaxThumbnailWidth * $SrcImage->YSize()) / $SrcImage->XSize();
273 }
274 else
275 {
276 $this->ThumbnailWidth = ($MaxThumbnailHeight * $SrcImage->XSize()) / $SrcImage->YSize();
277 $this->ThumbnailHeight = $MaxThumbnailHeight;
278 }
279
280 # save image attributes to database
281 $this->SaveImageInfo();
282 }
283
284 # ---- PRIVATE INTERFACE -------------------------------------------------
285
286 var $Id;
287 var $FileName;
288 var $PreviewFileName;
289 var $ThumbnailFileName;
290 var $Format;
291 var $AltText;
292 var $Url;
293 var $PreviewUrl;
294 var $ThumbnailUrl;
295 var $Height;
296 var $Width;
297 var $PreviewHeight;
298 var $PreviewWidth;
299 var $ThumbnailHeight;
300 var $ThumbnailWidth;
301 var $DB;
302 var $ErrorStatus;
303
304 function CreateNewImage($FileName, $MaxWidth, $MaxHeight,
305 $MaxPreviewWidth, $MaxPreviewHeight,
306 $MaxThumbnailWidth, $MaxThumbnailHeight)
307 {
308 # if file does not exist or is not readable
309 if (!is_readable($FileName))
310 {
311 # set error status
312 $this->ErrorStatus = AI_FILEUNREADABLE;
313 }
314 else
315 {
316 # if image is invalid or unsupported type
317 $SrcImage = new Image($FileName);
318 if ($SrcImage->Status() != AI_OKAY)
319 {
320 # set error status
321 $this->ErrorStatus = $SrcImage->Status();
322 }
323 else
324 {
325 # retrieve image type
326 $this->Format = $SrcImage->Type();
327
328 # generate new image ID
329 $this->Id = $this->GenerateNewImageId();
330
331 # generate and set file names
332 $this->SetFileNames();
333
334 # if our image file name differs from file name passed in
335 if (realpath($this->FileName) != realpath($FileName))
336 {
337 # create image file
338 $SrcImage->SaveAs($this->FileName);
339
340 # if create failed set error status and bail out
341 if ($SrcImage->Status() != AI_OKAY)
342 {
343 echo "create failed<br>";
344 echo "Status: ".$SrcImage->Status()."<br>";
345 echo "Failed Command: ".$SrcImage->FailedExternalCommand()."<br>";
346 echo "Missing External Executables: ";
347 print_r(Image::MissingExternalExecutables());
348 echo "<br>";
349 $this->ErrorStatus = $SrcImage->Status();
350 return;
351 }
352 }
353
354 # scale the original image if necessary
355 $MaxWidth = min($MaxWidth, $SrcImage->XSize());
356 $MaxHeight = min($MaxHeight, $SrcImage->YSize());
357 $SrcImage->ScaleTo($MaxWidth, $MaxHeight, TRUE);
358
359 # save and reload image info
360 $SrcImage->SaveAs($this->FileName);
361 $SrcImage = new Image($this->FileName);
362
363 # retrieve image width and height
364 $this->Height = $SrcImage->YSize();
365 $this->Width = $SrcImage->XSize();
366
367 # generate preview image and calculate width and height
368 $MaxPreviewWidth = min($MaxPreviewWidth, $this->Width);
369 $MaxPreviewHeight = min($MaxPreviewHeight, $this->Height);
370 $SrcImage->ScaleTo($MaxPreviewWidth, $MaxPreviewHeight, TRUE);
371 $SrcImage->SaveAs($this->PreviewFileName, IMGTYPE_JPEG);
372 if ($SrcImage->Status() != AI_OKAY)
373 {
374 echo "preview save as failed<br>";
375 $this->ErrorStatus = $SrcImage->Status();
376 return;
377 }
378 if (($this->Width * $MaxPreviewHeight)
379 > ($this->Height * $MaxPreviewWidth))
380 {
381 $this->PreviewWidth = $MaxPreviewWidth;
382 $this->PreviewHeight =
383 ($MaxPreviewWidth * $SrcImage->YSize()) / $SrcImage->XSize();
384 }
385 else
386 {
387 $this->PreviewWidth =
388 ($MaxPreviewHeight * $SrcImage->XSize()) / $SrcImage->YSize();
389 $this->PreviewHeight = $MaxPreviewHeight;
390 }
391
392 # generate thumbnail image and calculate width and height
393 $MaxThumbnailWidth = min($MaxThumbnailWidth, $this->Width);
394 $MaxThumbnailHeight = min($MaxThumbnailHeight, $this->Height);
395 $SrcImage->ScaleTo($MaxThumbnailWidth, $MaxThumbnailHeight, TRUE);
396 $SrcImage->SaveAs($this->ThumbnailFileName, IMGTYPE_JPEG);
397 if ($SrcImage->Status() != AI_OKAY)
398 {
399 echo "thumbnail SaveAs failed.<br>";
400 $this->ErrorStatus = $SrcImage->Status();
401 return;
402 }
403 if (($this->Width * $MaxThumbnailHeight)
404 > ($this->Height * $MaxThumbnailWidth))
405 {
406 $this->ThumbnailWidth = $MaxThumbnailWidth;
407 $this->ThumbnailHeight =
408 ($MaxThumbnailWidth * $SrcImage->YSize()) / $SrcImage->XSize();
409 }
410 else
411 {
412 $this->ThumbnailWidth = ($MaxThumbnailHeight * $SrcImage->XSize()) / $SrcImage->YSize();
413 $this->ThumbnailHeight = $MaxThumbnailHeight;
414 }
415
416 # save image attributes to database
417 $this->SaveImageInfo();
418 }
419 }
420 }
421
422 function LoadImageInfo($ImageId)
423 {
424 # save image ID
425 $this->Id = $ImageId;
426
427 # load image record from database
428 $this->DB->Query("SELECT * FROM Images WHERE ImageId = ".$ImageId);
429
430 # if the ID is invalid
431 if (!$this->DB->NumRowsSelected())
432 {
433 $this->ErrorStatus = AI_INTERNALERROR;
434 return;
435 }
436
437 $Record = $this->DB->FetchRow();
438
439 # load in values from record
440 $this->Format = $Record["Format"];
441 $this->AltText = $Record["AltText"];
442 $this->Height = $Record["Height"];
443 $this->Width = $Record["Width"];
444 $this->PreviewHeight = $Record["PreviewHeight"];
445 $this->PreviewWidth = $Record["PreviewWidth"];
446 $this->ThumbnailHeight = $Record["ThumbnailHeight"];
447 $this->ThumbnailWidth = $Record["ThumbnailWidth"];
448
449 # generate file names
450 $this->SetFileNames();
451 }
452
453 function CreateCopyOfImage($SrcImage)
454 {
455 $Image = new Image($SrcImage->Url());
456 if ($Image->Status() != AI_OKAY)
457 {
458 # set error status
459 $this->ErrorStatus = $Image->Status();
460 return;
461 }
462
463 # generate new image ID
464 $this->Id = $this->GenerateNewImageId();
465
466 # generate file names
467 $this->SetFileNames();
468
469 # copy attributes from source image
470 $this->Format = $SrcImage->Format();
471 $this->AltText = $SrcImage->AltText();
472 $this->Width = $SrcImage->Width();
473 $this->Height = $SrcImage->Height();
474 $this->PreviewWidth = $SrcImage->PreviewWidth();
475 $this->PreviewHeight = $SrcImage->PreviewHeight();
476 $this->ThumbnailWidth = $SrcImage->ThumbnailWidth();
477 $this->ThumbnailHeight = $SrcImage->ThumbnailHeight();
478
479 # copy source image files
480 copy($SrcImage->Url(), $this->FileName);
481 copy($SrcImage->PreviewUrl(), $this->PreviewFileName);
482 copy($SrcImage->ThumbnailUrl(), $this->ThumbnailFileName);
483
484 # save image attributes to database
485 $this->SaveImageInfo();
486 }
487
488 # generate and save image, preview, and thumnail file names
489 # (requires image ID and format to be set beforehand)
490 function SetFileNames()
491 {
492 if (Image::Extension($this->Format))
493 {
494 $FileExtension = Image::Extension($this->Format);
495 }
496 else
497 {
498 $FileExtension = "";
499 }
500
501 $this->FileName = self::IMAGE_PATH . "Img--"
502 .sprintf("%08d.", $this->Id).$FileExtension;
503 $this->PreviewFileName = self::PREVIEW_PATH . "Preview--"
504 .sprintf("%08d.", $this->Id).$FileExtension;
505 $this->ThumbnailFileName = self::THUMBNAIL_PATH . "Thumb--"
506 .sprintf("%08d.", $this->Id).$FileExtension;
507 }
508
509 # retrieve next image ID
510 function GenerateNewImageId()
511 {
512 # look up highest image ID in database
513 $CurrentHighestId = $this->DB->Query("SELECT ImageId FROM Images"
514 ." ORDER BY ImageId DESC LIMIT 1",
515 "ImageId");
516
517 # return next highest ID or 1 if no ID yet used
518 return ($CurrentHighestId > 0) ? ($CurrentHighestId + 1) : 1;
519 }
520
521 # store image attributes to database
522 function SaveImageInfo()
523 {
524 # look for existing image record with matching ID
525 $RecordCount = $this->DB->Query("SELECT COUNT(*) AS RecordCount FROM Images"
526 ." WHERE ImageId = ".$this->Id,
527 "RecordCount");
528
529 # if matching ID found
530 if ($RecordCount > 0)
531 {
532 # update existing image record
533 $this->DB->Query("UPDATE Images SET"
534 ." Format = '" .$this->Format."',"
535 ." AltText = '" .addslashes($this->AltText)."',"
536 ." Height = '" .$this->Height."',"
537 ." Width = '" .$this->Width."',"
538 ." PreviewHeight = '" .$this->PreviewHeight."',"
539 ." PreviewWidth = '" .$this->PreviewWidth."',"
540 ." ThumbnailHeight = '".$this->ThumbnailHeight."',"
541 ." ThumbnailWidth = '" .$this->ThumbnailWidth."'"
542 ." WHERE ImageId = ".$this->Id);
543 }
544 else
545 {
546 # add new image record
547 $this->DB->Query("INSERT INTO Images SET"
548 ." ImageId = '" .$this->Id."',"
549 ." Format = '" .$this->Format."',"
550 ." AltText = '" .addslashes($this->AltText)."',"
551 ." Height = '" .$this->Height."',"
552 ." Width = '" .$this->Width."',"
553 ." PreviewHeight = '" .$this->PreviewHeight."',"
554 ." PreviewWidth = '" .$this->PreviewWidth."',"
555 ." ThumbnailHeight = '".$this->ThumbnailHeight."',"
556 ." ThumbnailWidth = '" .$this->ThumbnailWidth."'");
557 }
558 }
559 }