CWIS Developer Documentation
File.php
Go to the documentation of this file.
1 <?PHP
2 
3 #
4 # FILE: File.php
5 #
6 # Copyright 2010 Edward Almasy and Internet Scout
7 # http://scout.wisc.edu
8 #
9 
10 
11 class File {
12 
13  # ---- PUBLIC INTERFACE --------------------------------------------------
14 
15  # status codes (set by constructor and returned by File::Status())
16  const FILESTAT_OK = 0;
17  const FILESTAT_COPYERROR = 1;
22 
23  # object constructor
24  function File($IdOrFileName, $ResourceId = NULL, $FieldId = NULL,
25  $DesiredFileName = NULL, $CheckFileLength = TRUE)
26  {
27  # assume constructor will succeed
28  $this->Status = self::FILESTAT_OK;
29 
30  # get our own database handle
31  $DB = new Database();
32  $this->DB = $DB;
33 
34  # if ID supplied
35  if (is_int($IdOrFileName))
36  {
37  # set file ID from supplied value
38  $this->Id = intval($IdOrFileName);
39 
40  # load file info from database
41  $DB->Query("SELECT * FROM Files WHERE FileId = ".$this->Id);
42  $this->DBFields = $DB->FetchRow();
43 
44  # if the image wasn't found in the database
45  if (!$DB->NumRowsSelected())
46  {
47  $this->Status = self::FILESTAT_DOESNOTEXIST;
48  }
49  }
50  # else if file name and resource ID and field ID supplied
51  elseif (strlen($IdOrFileName) && ($ResourceId != NULL) && ($FieldId != NULL))
52  {
53  # if file does not exist
54  $TempFileName = $IdOrFileName;
55  if (!file_exists($TempFileName) || !is_readable($TempFileName))
56  {
57  # set status indicating appropriate error
58  $this->Status = file_exists($TempFileName)
59  ? self::FILESTAT_DOESNOTEXIST : self::FILESTAT_UNREADABLE;
60  }
61  else
62  {
63  # if we were asked to check file length and file was zero length
64  $FileLength = filesize($TempFileName);
65  if ($CheckFileLength && !$FileLength)
66  {
67  # set status indicating zero length file
68  $this->Status = self::FILESTAT_ZEROLENGTH;
69  }
70  else
71  {
72  # generate secret string (used to protect from unauthorized download)
73  srand((double)microtime() * 1000000);
74  $SecretString = sprintf("%04X", rand(1, 30000));
75 
76  # attempt to get file type
77  $FileType = "";
78  if (function_exists("finfo_open"))
79  {
80  $FInfoHandle = finfo_open(FILEINFO_MIME);
81 
82  if ($FInfoHandle)
83  {
84  $FInfoMime = finfo_file($FInfoHandle, $TempFileName);
85  finfo_close($FInfoHandle);
86 
87  if ($FInfoMime)
88  {
89  $FileType = $FInfoMime;
90  }
91  }
92  }
93  else if (function_exists("mime_content_type"))
94  {
95  # mime_content_type has been deprecated, but it may be
96  # the only way to get the mimetype for PHP < 5.3
97  $MimeType = mime_content_type($TempFileName);
98 
99  if ($MimeType)
100  {
101  $FileType = $MimeType;
102  }
103  }
104 
105  # add file info to database
106  $BaseFileName = $DesiredFileName
107  ? basename($DesiredFileName) : basename($TempFileName);
108  $DB->Query("INSERT INTO Files"
109  ." (ResourceId, FieldId, FileName, FileLength, FileType,"
110  ." SecretString)"
111  ." VALUES ("
112  .intval($ResourceId).", "
113  .intval($FieldId).", "
114  ."'".addslashes($BaseFileName)."', "
115  .$FileLength.", "
116  ."'".$FileType."', "
117  ."'".$SecretString."')");
118 
119  # retrieve ID of new file
120  $this->Id = $DB->LastInsertId("Files");
121 
122  # load file info back in from database
123  $DB->Query("SELECT * FROM Files WHERE FileId = ".$this->Id);
124  $this->DBFields = $DB->FetchRow();
125 
126  # copy file to storage
127  $CopySucceeded = copy($IdOrFileName, $this->GetNameOfStoredFile());
128 
129  # if copy failed
130  if (!$CopySucceeded)
131  {
132  # remove file info from database
133  $DB->Query("DELETE FROM Files WHERE FileId = ".$this->Id);
134 
135  # set status indicating constructor failed
136  $this->Status = self::FILESTAT_COPYERROR;
137  }
138  }
139  }
140  }
141  else
142  {
143  # set status indicating constructor failed
144  $this->Status = self::FILESTAT_PARAMERROR;
145  }
146  }
147 
148  # return object status (used to report errors occurring in constructor)
149  function Status() { return $this->Status; }
150 
151  # get various attributes
152  function Id() { return $this->Id; }
153  function Name() { return $this->DBFields["FileName"]; }
154  function GetLength() { return $this->DBFields["FileLength"]; }
155  function GetType() { return $this->DBFields["FileType"]; }
156 
157  # get/set various attributes
158  function Comment($NewValue = DB_NOVALUE)
159  { return $this->UpdateValue("FileComment", $NewValue); }
160  function FieldId($NewValue = DB_NOVALUE)
161  { return $this->UpdateValue("FieldId", $NewValue); }
162  function ResourceId($NewValue = DB_NOVALUE)
163  { return $this->UpdateValue("ResourceId", $NewValue); }
164 
165  # get MIME type (defaults to "application/octet-stream" if not available)
166  function GetMimeType()
167  {
168  return strlen($this->GetType())
169  ? $this->GetType() : "application/octet-stream";
170  }
171 
172  # get link for downloading file
173  function GetLink()
174  {
175  global $AF;
176 
177  # if .htaccess files are supported, use the redirect that includes
178  # the file name so that browsers don't use index.php as the name
179  # for the downloaded file
180  if ($AF->HtaccessSupport())
181  {
182  return "downloads/".$this->Id."/".rawurlencode($this->Name());
183  }
184 
185  # otherwise use the download portal
186  else
187  {
188  return "index.php?P=DownloadFile&Id=".$this->Id;
189  }
190  }
191 
192  # delete file (other methods are invalid after calling this!)
193  function Delete()
194  {
195  # remove file entry from DB
196  $this->DB->Query("DELETE FROM Files WHERE FileId = ".$this->Id);
197 
198  # delete file
199  $FileName = $this->GetNameOfStoredFile();
200  if (file_exists($FileName))
201  {
202  unlink($FileName);
203  }
204  }
205 
206  # retrieve actual name of stored file
208  {
209  return sprintf("FileStorage/%06d-%s-%s",
210  $this->Id, $this->DBFields["SecretString"], $this->Name());
211  }
212 
213 
214  # ---- PRIVATE INTERFACE -------------------------------------------------
215 
216  private $DB;
217  private $Status;
218  private $Id;
219  private $DBFields;
220 
221  # convenience function to supply parameters to Database->UpdateValue()
222  private function UpdateValue($FieldName, $NewValue)
223  {
224  return $this->DB->UpdateValue("Files", $FieldName, $NewValue,
225  "FileId = ".intval($this->Id),
226  $this->DBFields, TRUE);
227  }
228 }
229 
230 
231 ?>