1<?php 2/********************************************************************* 3 class.attachment.php 4 5 Attachment Handler - mainly used for lookup...doesn't save! 6 7 Peter Rotich <peter@osticket.com> 8 Copyright (c) 2006-2013 osTicket 9 http://www.osticket.com 10 11 Released under the GNU General Public License WITHOUT ANY WARRANTY. 12 See LICENSE.TXT for details. 13 14 vim: expandtab sw=4 ts=4 sts=4: 15**********************************************************************/ 16require_once(INCLUDE_DIR.'class.ticket.php'); 17require_once(INCLUDE_DIR.'class.file.php'); 18 19class Attachment extends VerySimpleModel { 20 static $meta = array( 21 'table' => ATTACHMENT_TABLE, 22 'pk' => array('id'), 23 'select_related' => array('file'), 24 'joins' => array( 25 'draft' => array( 26 'constraint' => array( 27 'type' => "'D'", 28 'object_id' => 'Draft.id', 29 ), 30 ), 31 'file' => array( 32 'constraint' => array( 33 'file_id' => 'AttachmentFile.id', 34 ), 35 ), 36 'thread_entry' => array( 37 'constraint' => array( 38 'type' => "'H'", 39 'object_id' => 'ThreadEntry.id', 40 ), 41 ), 42 ), 43 ); 44 45 var $object; 46 47 function getId() { 48 return $this->id; 49 } 50 51 function getFileId() { 52 return $this->file_id; 53 } 54 55 function getFile() { 56 return $this->file; 57 } 58 59 function getFilename() { 60 return $this->name ?: $this->file->name; 61 } 62 63 function getName() { 64 return $this->getFilename(); 65 } 66 67 function getHashtable() { 68 return $this->ht; 69 } 70 71 function getInfo() { 72 return $this->getHashtable(); 73 } 74 75 function getObject() { 76 77 if (!isset($this->object)) 78 $this->object = ObjectModel::lookup( 79 $this->ht['object_id'], $this->ht['type']); 80 81 return $this->object; 82 } 83 84 static function lookupByFileHash($hash, $objectId=0) { 85 $file = static::objects() 86 ->filter(array('file__key' => $hash)); 87 88 if ($objectId) 89 $file->filter(array('object_id' => $objectId)); 90 91 return $file->first(); 92 } 93 94 static function lookup($var, $objectId=0) { 95 return (is_string($var)) 96 ? static::lookupByFileHash($var, $objectId) 97 : parent::lookup($var); 98 } 99} 100 101class GenericAttachments 102extends InstrumentedList { 103 104 var $lang; 105 106 function getId() { return $this->key['object_id']; } 107 function getType() { return $this->key['type']; } 108 function getMimeType() { return $this->getType(); } 109 /** 110 * Drop attachments whose file_id values are not in the included list, 111 * additionally, add new files whose IDs are in the list provided. 112 */ 113 function keepOnlyFileIds($ids, $inline=false, $lang=false) { 114 if (!$ids) $ids = array(); 115 foreach ($this as $A) { 116 if (!isset($ids[$A->file_id]) && $A->lang == $lang && $A->inline == $inline) 117 // Not in the $ids list, delete 118 $this->remove($A); 119 unset($ids[$A->file_id]); 120 } 121 $attachments = array(); 122 // Format $new for upload() with new name 123 foreach ($ids as $id=>$name) { 124 $attachments[] = array( 125 'id' => $id, 126 'name' => $name 127 ); 128 } 129 // Everything remaining in $attachments is truly new 130 $this->upload($attachments, $inline, $lang); 131 } 132 133 function upload($files, $inline=false, $lang=false) { 134 $i=array(); 135 if (!is_array($files)) 136 $files = array($files); 137 foreach ($files as $file) { 138 if (is_numeric($file)) 139 $fileId = $file; 140 elseif (is_array($file) && isset($file['id']) && $file['id']) 141 $fileId = $file['id']; 142 elseif (isset($file['tmp_name']) && ($F = AttachmentFile::upload($file))) 143 $fileId = $F->getId(); 144 elseif ($F = AttachmentFile::create($file)) 145 $fileId = $F->getId(); 146 else 147 continue; 148 149 $_inline = isset($file['inline']) ? $file['inline'] : $inline; 150 151 // Check if Attachment exists 152 if ($F && $this->key) 153 $existing = Attachment::objects()->filter(array( 154 'file__key' => $F->key, 155 'object_id' => $this->key['object_id'], 156 'type' => $this->key['type'] 157 ))->first(); 158 159 $att = $this->add(isset($existing) ? $existing : new Attachment(array( 160 'file_id' => $fileId, 161 'inline' => $_inline ? 1 : 0, 162 ))); 163 164 // Record varying file names in the attachment record 165 if (is_array($file) && isset($file['name'])) { 166 $filename = $file['name']; 167 } 168 if ($filename) { 169 // This should be a noop since the ORM caches on PK 170 $file = $F ?: AttachmentFile::lookup($fileId); 171 // XXX: This is not Unicode safe 172 if ($file && 0 !== strcasecmp($file->name, $filename)) 173 $att->name = $filename; 174 } 175 if ($lang) 176 $att->lang = $lang; 177 178 // File may already be associated with the draft (in the 179 // event it was deleted and re-added) 180 $att->save(); 181 $i[] = $fileId; 182 } 183 return $i; 184 } 185 186 function save($file, $inline=true) { 187 $ids = $this->upload($file, $inline); 188 return $ids[0]; 189 } 190 191 function getInlines($lang=false) { return $this->_getList(false, true, $lang); } 192 function getSeparates($lang=false) { return $this->_getList(true, false, $lang); } 193 function getAll($lang=false) { return $this->_getList(true, true, $lang); } 194 function count($lang=false) { return count($this->getSeparates($lang)); } 195 196 function _getList($separates=false, $inlines=false, $lang=false) { 197 $base = $this; 198 199 if ($separates && !$inlines) 200 $base = $base->filter(array('inline' => 0)); 201 elseif (!$separates && $inlines) 202 $base = $base->filter(array('inline' => 1)); 203 204 if ($lang) 205 $base = $base->filter(array('lang' => $lang)); 206 207 return $base; 208 } 209 210 function delete($file_id) { 211 return $this->objects()->filter(array('file_id'=>$file_id))->delete(); 212 } 213 214 function deleteAll($inline_only=false){ 215 if ($inline_only) 216 return $this->objects()->filter(array('inline' => 1))->delete(); 217 218 return parent::expunge(); 219 } 220 221 function deleteInlines() { 222 return $this->deleteAll(true); 223 } 224 225 static function forIdAndType($id, $type) { 226 return new static(array( 227 'Attachment', 228 array('object_id' => $id, 'type' => $type) 229 )); 230 } 231} 232?> 233