CWIS Developer Documentation
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;
290  var $Format;
291  var $AltText;
292  var $Url;
295  var $Height;
296  var $Width;
301  var $DB;
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: ";
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
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 }