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