3 +--------------------------------------------------------------------+
4 | CiviCRM version 4.3 |
5 +--------------------------------------------------------------------+
6 | Copyright CiviCRM LLC (c) 2004-2013 |
7 +--------------------------------------------------------------------+
8 | This file is a part of CiviCRM. |
10 | CiviCRM is free software; you can copy, modify, and distribute it |
11 | under the terms of the GNU Affero General Public License |
12 | Version 3, 19 November 2007 and the CiviCRM Licensing Exception. |
14 | CiviCRM is distributed in the hope that it will be useful, but |
15 | WITHOUT ANY WARRANTY; without even the implied warranty of |
16 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
17 | See the GNU Affero General Public License for more details. |
19 | You should have received a copy of the GNU Affero General Public |
20 | License and the CiviCRM Licensing Exception along |
21 | with this program; if not, contact CiviCRM LLC |
22 | at info[AT]civicrm[DOT]org. If you have questions about the |
23 | GNU Affero General Public License or the licensing of CiviCRM, |
24 | see the CiviCRM license FAQ at http://civicrm.org/licensing |
25 +--------------------------------------------------------------------+
31 * @copyright CiviCRM LLC (c) 2004-2013
37 * BAO object for crm_log table
39 class CRM_Core_BAO_File
extends CRM_Core_DAO_File
{
41 static $_signableFields = array('entityTable', 'entityID', 'fileID');
43 static function path($fileID, $entityID, $entityTable = NULL) {
44 $entityFileDAO = new CRM_Core_DAO_EntityFile();
46 $entityFileDAO->entity_table
= $entityTable;
48 $entityFileDAO->entity_id
= $entityID;
49 $entityFileDAO->file_id
= $fileID;
51 if ($entityFileDAO->find(TRUE)) {
52 $fileDAO = new CRM_Core_DAO_File();
53 $fileDAO->id
= $fileID;
54 if ($fileDAO->find(TRUE)) {
55 $config = CRM_Core_Config
::singleton();
56 $path = $config->customFileUploadDir
. $fileDAO->uri
;
58 if (file_exists($path) && is_readable($path)) {
59 return array($path, $fileDAO->mime_type
);
64 return array(NULL, NULL);
68 static function filePostProcess(
76 $uploadName = 'uploadFile',
80 CRM_Core_Error
::fatal(ts('Mime Type is now a required parameter'));
83 $config = CRM_Core_Config
::singleton();
85 $path = explode('/', $data);
86 $filename = $path[count($path) - 1];
88 // rename this file to go into the secure directory
90 $directoryName = $config->customFileUploadDir
. $entitySubtype . DIRECTORY_SEPARATOR
. $entityID;
93 $directoryName = $config->customFileUploadDir
;
96 CRM_Utils_File
::createDir($directoryName);
98 if (!rename($data, $directoryName . DIRECTORY_SEPARATOR
. $filename)) {
99 CRM_Core_Error
::fatal(ts('Could not move custom file to custom upload directory'));
104 if ($overwrite && $fileTypeID) {
105 list($sql, $params) = self
::sql($entityTable, $entityID, $fileTypeID);
108 list($sql, $params) = self
::sql($entityTable, $entityID, NULL);
111 $dao = CRM_Core_DAO
::executeQuery($sql, $params);
114 $fileDAO = new CRM_Core_DAO_File();
116 if (isset($dao->cfID
) && $dao->cfID
) {
118 $fileDAO->id
= $dao->cfID
;
119 unlink($directoryName . DIRECTORY_SEPARATOR
. $dao->uri
);
122 if (!empty($fileParams)) {
123 $fileDAO->copyValues($fileParams);
126 $fileDAO->uri
= $filename;
127 $fileDAO->mime_type
= $mimeType;
128 $fileDAO->file_type_id
= $fileTypeID;
129 $fileDAO->upload_date
= date('Ymdhis');
132 // need to add/update civicrm_entity_file
133 $entityFileDAO = new CRM_Core_DAO_EntityFile();
134 if (isset($dao->cefID
) && $dao->cefID
) {
135 $entityFileDAO->id
= $dao->cefID
;
137 $entityFileDAO->entity_table
= $entityTable;
138 $entityFileDAO->entity_id
= $entityID;
139 $entityFileDAO->file_id
= $fileDAO->id
;
140 $entityFileDAO->save();
143 if (!empty($fileParams['tag'])) {
144 CRM_Core_BAO_EntityTag
::create($fileParams['tag'], 'civicrm_file', $entityFileDAO->id
);
148 if (isset($fileParams['attachment_taglist']) && !empty($fileParams['attachment_taglist'])) {
149 CRM_Core_Form_Tag
::postProcess($fileParams['attachment_taglist'], $entityFileDAO->id
, 'civicrm_file', CRM_Core_DAO
::$_nullObject);
152 // lets call the post hook here so attachments code can do the right stuff
153 CRM_Utils_Hook
::post($op, 'File', $fileDAO->id
, $fileDAO);
157 * The $useWhere is used so that the signature matches the parent class
159 public function delete($useWhere = false) {
160 list($fileID, $entityID, $fieldID) = func_get_args();
162 $fileDAO = new CRM_Core_DAO_File();
163 $fileDAO->id
= $fileID;
164 if (!$fileDAO->find(TRUE)) {
165 CRM_Core_Error
::fatal();
168 // lets call a pre hook before the delete, so attachments hooks can get the info before things
170 CRM_Utils_Hook
::pre('delete', 'File', $fileID, $fileDAO);
172 // get the table and column name
173 list($tableName, $columnName, $groupID) = CRM_Core_BAO_CustomField
::getTableColumnGroup($fieldID);
175 $entityFileDAO = new CRM_Core_DAO_EntityFile();
176 $entityFileDAO->file_id
= $fileID;
177 $entityFileDAO->entity_id
= $entityID;
178 $entityFileDAO->entity_table
= $tableName;
180 if (!$entityFileDAO->find(TRUE)) {
181 CRM_Core_Error
::fatal();
184 $entityFileDAO->delete();
187 // also set the value to null of the table and column
188 $query = "UPDATE $tableName SET $columnName = null WHERE $columnName = %1";
189 $params = array(1 => array($fileID, 'Integer'));
190 CRM_Core_DAO
::executeQuery($query, $params);
194 * delete all the files and associated object associated with this
197 static function deleteEntityFile($entityTable, $entityID, $fileTypeID = NULL, $fileID = NULL) {
198 if (empty($entityTable) ||
empty($entityID)) {
202 $config = CRM_Core_Config
::singleton();
204 list($sql, $params) = self
::sql($entityTable, $entityID, $fileTypeID, $fileID);
205 $dao = CRM_Core_DAO
::executeQuery($sql, $params);
209 while ($dao->fetch()) {
210 $cfIDs[$dao->cfID
] = $dao->uri
;
211 $cefIDs[] = $dao->cefID
;
214 if (!empty($cefIDs)) {
215 $cefIDs = implode(',', $cefIDs);
216 $sql = "DELETE FROM civicrm_entity_file where id IN ( $cefIDs )";
217 CRM_Core_DAO
::executeQuery($sql);
220 if (!empty($cfIDs)) {
221 // Delete file only if there no any entity using this file.
222 $deleteFiles = array();
223 foreach ($cfIDs as $fId => $fUri) {
224 //delete tags from entity tag table
226 'entity_table' => 'civicrm_file',
230 CRM_Core_BAO_EntityTag
::del($tagParams);
232 if (!CRM_Core_DAO
::getFieldValue('CRM_Core_DAO_EntityFile', $fId, 'id', 'file_id')) {
233 unlink($config->customFileUploadDir
. DIRECTORY_SEPARATOR
. $fUri);
234 $deleteFiles[$fId] = $fId;
238 if (!empty($deleteFiles)) {
239 $deleteFiles = implode(',', $deleteFiles);
240 $sql = "DELETE FROM civicrm_file where id IN ( $deleteFiles )";
241 CRM_Core_DAO
::executeQuery($sql);
247 * get all the files and associated object associated with this
250 static function getEntityFile($entityTable, $entityID, $addDeleteArgs = false) {
251 if (empty($entityTable) ||
!$entityID) {
256 $config = CRM_Core_Config
::singleton();
258 list($sql, $params) = self
::sql($entityTable, $entityID, NULL);
259 $dao = CRM_Core_DAO
::executeQuery($sql, $params);
261 while ($dao->fetch()) {
262 $result['fileID'] = $dao->cfID
;
263 $result['entityID'] = $dao->cefID
;
264 $result['mime_type'] = $dao->mime_type
;
265 $result['fileName'] = $dao->uri
;
266 $result['description'] = $dao->description
;
267 $result['cleanName'] = CRM_Utils_File
::cleanFileName($dao->uri
);
268 $result['fullPath'] = $config->customFileUploadDir
. DIRECTORY_SEPARATOR
. $dao->uri
;
269 $result['url'] = CRM_Utils_System
::url('civicrm/file', "reset=1&id={$dao->cfID}&eid={$entityID}");
270 $result['href'] = "<a href=\"{$result['url']}\">{$result['cleanName']}</a>";
271 $result['tag'] = CRM_Core_BAO_EntityTag
::getTag($dao->cfID
, 'civicrm_file');
272 if ($addDeleteArgs) {
273 $result['deleteURLArgs'] = self
::deleteURLArgs($entityTable, $entityID, $dao->cfID
);
275 $results[$dao->cfID
] = $result;
279 $tags = CRM_Core_PseudoConstant
::tag();
281 foreach($results as &$values) {
282 if (!empty($values['tag'])) {
284 foreach( $values['tag'] as $tid ) {
285 $tagNames[] = $tags[$tid];
287 $values['tag'] = implode(', ', $tagNames);
297 static function sql($entityTable, $entityID, $fileTypeID = NULL, $fileID = NULL) {
299 SELECT CF.id as cfID,
301 CF.mime_type as mime_type,
302 CF.description as description,
304 FROM civicrm_file AS CF
305 LEFT JOIN civicrm_entity_file AS CEF ON ( CEF.file_id = CF.id )
306 WHERE CEF.entity_table = %1
307 AND CEF.entity_id = %2";
310 1 => array($entityTable, 'String'),
311 2 => array($entityID, 'Integer'),
314 if ($fileTypeID !== NULL) {
315 $sql .= " AND CF.file_type_id = %3";
316 $params[3] = array($fileTypeID, 'Integer');
319 if ($fileID !== NULL) {
320 $sql .= " AND CF.id = %4";
321 $params[4] = array($fileID, 'Integer');
324 return array($sql, $params);
327 static function buildAttachment(&$form, $entityTable, $entityID = NULL, $numAttachments = NULL, $ajaxDelete = FALSE) {
329 if (!$numAttachments) {
330 $numAttachments = CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'max_attachments');
332 // Assign maxAttachments count to template for help message
333 $form->assign('maxAttachments', $numAttachments);
335 $config = CRM_Core_Config
::singleton();
336 // set default max file size as 2MB
337 $maxFileSize = $config->maxFileSize ?
$config->maxFileSize
: 2;
339 $currentAttachmentInfo = self
::getEntityFile($entityTable, $entityID, TRUE);
340 $totalAttachments = 0;
341 if ($currentAttachmentInfo) {
342 $totalAttachments = count($currentAttachmentInfo);
343 $form->add('checkbox', 'is_delete_attachment', ts('Delete All Attachment(s)'));
344 $form->assign('currentAttachmentInfo', $currentAttachmentInfo);
347 $form->assign('currentAttachmentInfo', NULL);
350 if ( $totalAttachments ) {
351 if ($totalAttachments >= $numAttachments) {
355 $numAttachments -= $totalAttachments;
359 $form->assign('numAttachments', $numAttachments);
361 $tags = CRM_Core_BAO_Tag
::getTags('civicrm_file');
364 $parentNames = CRM_Core_BAO_Tag
::getTagSet('civicrm_file');
367 for ($i = 1; $i <= $numAttachments; $i++
) {
368 $form->addElement('file', "attachFile_$i", ts('Attach File'), 'size=30 maxlength=60');
369 $form->setMaxFileSize($maxFileSize * 1024 * 1024);
370 $form->addRule("attachFile_$i",
371 ts('File size should be less than %1 MByte(s)',
372 array(1 => $maxFileSize)
375 $maxFileSize * 1024 * 1024
377 $form->addElement('text', "attachDesc_$i", ts('Description'), 'size=40 maxlength=255');
380 $form->add('select', "tag_$i", ts('Tags'), $tags, FALSE,
381 array('id' => "tags_$i", 'multiple' => 'multiple', 'title' => ts('- select -'))
386 // build tagset widget
387 CRM_Core_Form_Tag
::buildQuickForm($form, $parentNames, 'civicrm_file', NULL, FALSE, TRUE, FALSE);
391 * Function to return a clean url string and the number of attachment for a
392 * given entityTable, entityID
394 * @param $entityTable string The entityTable to which the file is attached
395 * @param $entityID int The id of the object in the above entityTable
396 * @param $separator string The string separator where to implode the urls
398 * @return array An array with 2 elements. The string and the number of attachments
401 static function attachmentInfo($entityTable, $entityID, $separator = '<br />') {
406 $currentAttachments = self
::getEntityFile($entityTable, $entityID);
407 if (!empty($currentAttachments)) {
408 $currentAttachmentURL = array();
409 foreach ($currentAttachments as $fileID => $attach) {
410 $currentAttachmentURL[] = $attach['href'];
412 return implode($separator, $currentAttachmentURL);
417 static function formatAttachment(
424 // delete current attachments if applicable
425 if ($entityID && CRM_Utils_Array
::value('is_delete_attachment', $formValues)) {
426 CRM_Core_BAO_File
::deleteEntityFile($entityTable, $entityID);
429 $numAttachments = CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'max_attachments');
431 $now = date('Ymdhis');
433 // setup all attachments
434 for ($i = 1; $i <= $numAttachments; $i++
) {
435 $attachName = "attachFile_$i";
436 $attachDesc = "attachDesc_$i";
437 $attachTags = "tag_$i";
438 $attachFreeTags = "attachment_taglist_$i";
439 if (isset($formValues[$attachName]) && !empty($formValues[$attachName])) {
440 // add static tags if selects
441 $tagParams = array();
442 if (!empty($formValues[$attachTags])) {
443 foreach ($formValues[$attachTags] as $tag) {
444 $tagParams[$tag] = 1;
448 // we dont care if the file is empty or not
451 'uri' => $formValues[$attachName]['name'],
452 'type' => $formValues[$attachName]['type'],
453 'location' => $formValues[$attachName]['name'],
454 'description' => $formValues[$attachDesc],
455 'upload_date' => $now,
457 'attachment_taglist' => CRM_Utils_Array
::value($attachFreeTags, $formValues, array())
460 $params[$attachName] = $fileParams;
465 static function processAttachment(&$params, $entityTable, $entityID) {
466 $numAttachments = CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'max_attachments');
468 for ($i = 1; $i <= $numAttachments; $i++
) {
470 isset($params["attachFile_$i"]) &&
471 is_array($params["attachFile_$i"])
473 self
::filePostProcess(
474 $params["attachFile_$i"]['location'],
480 $params["attachFile_$i"],
482 $params["attachFile_$i"]['type']
488 static function uploadNames() {
489 $numAttachments = CRM_Core_BAO_Setting
::getItem(CRM_Core_BAO_Setting
::SYSTEM_PREFERENCES_NAME
, 'max_attachments');
492 for ($i = 1; $i <= $numAttachments; $i++
) {
493 $names[] = "attachFile_{$i}";
495 $names[] = 'uploadFile';
500 * Function to copy/attach an existing file to a different entity
503 static function copyEntityFile($oldEntityTable, $oldEntityId, $newEntityTable, $newEntityId) {
504 $oldEntityFile = new CRM_Core_DAO_EntityFile();
505 $oldEntityFile->entity_id
= $oldEntityId;
506 $oldEntityFile->entity_table
= $oldEntityTable;
507 $oldEntityFile->find();
509 while ($oldEntityFile->fetch()) {
510 $newEntityFile = new CRM_Core_DAO_EntityFile();
511 $newEntityFile->entity_id
= $newEntityId;
512 $newEntityFile->entity_table
= $newEntityTable;
513 $newEntityFile->file_id
= $oldEntityFile->file_id
;
514 $newEntityFile->save();
518 static function deleteURLArgs($entityTable, $entityID, $fileID) {
519 $params['entityTable'] = $entityTable;
520 $params['entityID'] = $entityID;
521 $params['fileID'] = $fileID;
523 $signer = new CRM_Utils_Signer(CRM_Core_Key
::privateKey(), self
::$_signableFields);
524 $params['_sgn'] = $signer->sign($params);
525 return CRM_Utils_System
::makeQueryString($params);
529 * function to delete a file attachment from an entity table / entity ID
534 static function deleteAttachment( ) {
536 $params['entityTable'] = CRM_Utils_Request
::retrieve( 'entityTable', 'String' , CRM_Core_DAO
::$_nullObject, TRUE);
537 $params['entityID'] = CRM_Utils_Request
::retrieve( 'entityID' , 'Positive', CRM_Core_DAO
::$_nullObject, TRUE);
538 $params['fileID'] = CRM_Utils_Request
::retrieve( 'fileID' , 'Positive', CRM_Core_DAO
::$_nullObject, TRUE);
540 $signature = CRM_Utils_Request
::retrieve( '_sgn', 'String', CRM_Core_DAO
::$_nullObject, TRUE);
542 $signer = new CRM_Utils_Signer(CRM_Core_Key
::privateKey(), self
::$_signableFields);
543 if (! $signer->validate($signature, $params)) {
544 CRM_Core_Error
::fatal('Request signature is invalid');
547 CRM_Core_BAO_File
::deleteEntityFile($params['entityTable'], $params['entityID'], NULL, $params['fileID']);