1 <?php # vim:ts=2:sw=2:et:
2 /* For licensing and copyright terms, see the file named LICENSE */
4 //require_once 'MTrack/Changeset.php';
5 require_once 'MTrack/DB.php';
6 require_once 'MTrack/Config.php';
9 class MTrackAttachment {
11 static function add($object, $local_filename, $filename, MTrackChangeset $CS)
13 $size = filesize($local_filename);
17 $hash = self::import_file($local_filename);
18 $fp = fopen($local_filename, 'rb');
19 $q = MTrackDB::get()->prepare(
20 'insert into attachments (object, hash, filename, size, cid, payload)
21 values (?, ?, ?, ?, ?, ?)');
22 $q->bindValue(1, $object);
23 $q->bindValue(2, $hash);
24 $q->bindValue(3, $filename);
25 $q->bindValue(4, $size);
26 $q->bindValue(5, $CS->cid);
27 $q->bindValue(6, $fp, PDO::PARAM_LOB);
29 $CS->add("$object:@attachment:", '', $filename);
32 static function process_delete($relobj, MTrackChangeset $CS) {
33 if (!isset($_POST['delete_attachment'])) return;
34 if (!is_array($_POST['delete_attachment'])) return;
35 foreach ($_POST['delete_attachment'] as $name) {
36 $vars = explode('/', $name);
37 $filename = array_pop($vars);
38 $cid = array_pop($vars);
39 $object = join('/', $vars);
41 if ($object != $relobj) return;
42 MTrackDB::q('delete from attachments where object = ? and
43 cid = ? and filename = ?', $object, $cid, $filename);
44 $CS->add("$object:@attachment:", $filename, '');
48 /* this function is registered into sqlite and invoked from
49 * a trigger whenever an attachment row is deleted */
50 static function attachment_row_deleted($hash, $count)
53 // unlink the underlying file here
54 unlink(self::local_path($hash, false));
59 static function hash_file($filename)
61 return sha1_file($filename);
64 static function local_path($hash, $fetch = true)
66 $adir = MTrackConfig::get('core', 'vardir') . '/attach';
68 /* 40 hex digits: split into 16, 16, 4, 4 */
69 $a = substr($hash, 0, 16);
70 $b = substr($hash, 16, 16);
71 $c = substr($hash, 32, 4);
72 $d = substr($hash, 36, 4);
74 $dir = "$adir/$a/$b/$c";
77 mkdir($dir, 02777, true);
80 $filename = $dir . "/$d";
84 $fp = @fopen($filename, 'c+');
87 if ($st['size'] == 0) {
88 /* we get to fill it out */
90 $db = MTrackDB::get();
92 'select payload from attachments where hash = ?');
93 $q->execute(array($hash));
94 $q->bindColumn(1, $blob, PDO::PARAM_LOB);
96 if (is_string($blob)) {
99 stream_copy_to_stream($blob, $fp);
108 /* calculates the hash of the filename. If another file with
109 * the same hash does not already exist in the attachment area,
110 * the file is copied in.
111 * Returns the hash */
112 static function import_file($filename)
114 $h = self::hash_file($filename);
115 $dest = self::local_path($h, false);
116 if (!file_exists($dest)) {
117 if (is_uploaded_file($filename)) {
118 move_uploaded_file($filename, $dest);
119 } else if (!is_file($filename)) {
120 throw new Exception("$filename does not exist");
122 copy($filename, $dest);
128 static function renderDeleteList($object)
132 $atts = MTrackDB::q('
133 select * from attachments
134 left join changes on (attachments.cid = changes.cid)
135 where attachments.object = ? order by changedate, filename',
136 $object)->fetchAll(PDO::FETCH_ASSOC);
138 if (count($atts) == 0) return '';
143 <em>Select the checkbox to delete an attachment</em>
153 foreach ($atts as $row) {
154 $url = "{$ABSWEB}attachment.php/$object/$row[cid]/$row[filename]";
157 <td><input type='checkbox' name='delete_attachment[]'
158 value='$object/$row[cid]/$row[filename]'></td>
159 <td><a class='attachment' href='$url'>$row[filename]</a></td>
163 $html .= mtrack_username($row['who'], array(
166 " " . mtrack_date($row['changedate']) . "</td></tr>\n";
168 $html .= "</table><br>";
172 /* renders the attachment list for a given object */
173 static function renderList($object)
177 $atts = MTrackDB::q('
178 select * from attachments
179 left join changes on (attachments.cid = changes.cid)
180 where attachments.object = ? order by changedate, filename',
181 $object)->fetchAll(PDO::FETCH_ASSOC);
183 if (count($atts) == 0) return '';
187 $html = "<div class='attachment-list'><b>Attachments</b><ul>";
188 foreach ($atts as $row) {
189 $url = "{$ABSWEB}attachment.php/$object/$row[cid]/$row[filename]";
190 $html .= "<li><a class='attachment'" .
192 "$row[filename]</a> ($row[size]) added by " .
193 mtrack_username($row['who'], array(
196 " " . mtrack_date($row['changedate']);
198 list($width, $height) = getimagesize(self::local_path($row['hash']));
199 if ($width + $height) {
200 /* limit maximum size */
201 if ($width > $max_dim) {
202 $height *= $max_dim / $width;
205 if ($height > $max_dim) {
206 $width *= $max_dim / $height;
209 $html .= "<br><a href='$url'><img src='$url' width='$width' border='0' height='$height'></a>";
214 $html .= "</ul></div>";