/** * Creates an attachment to the specified data item. This will also pass * the attachment along for text extraction and indexing if requested. This * method supports the above createFrom*() methods; however it may also be * called directly. * * @param flag Data Item type flag. * @param integer Data Item ID. * @param boolean Is this a profile image attachment? * @param boolean Attempt to extract, store, and index the attachment's * text? * @param string Attachment title, or boolean false to create a title * automatically from the attachment's filename. * @param string The filename an attachment originally before any renaming. * @param string The temporary location where the file is currently stored * on the system where CATS is located. * @param string MIME content type (or '' if unknown). * @param string File's contents if a file is being created from text / * contents. Specify false if not creating a file by its * contents. * @param boolean Does this file actually exist? If true, the file will be * moved to the created attachment directory automatically. * If false, the caller is responsible. This has no effect * if $fileContents is not false. * @return boolean Was the attachment created successfully? */ public function createGeneric($dataItemType, $dataItemID, $isProfileImage, $extractText, $title, $originalFilename, $tempFilename, $contentType, $fileContents, $fileExists) { /* Make a 'safe' filename with only standard ASCII characters. */ $storedFilename = FileUtility::makeSafeFilename($originalFilename); /* Create an attachment title. */ $attachmentTitle = FileUtility::getFileWithoutExtension($originalFilename); /* Make attachment searchable. */ if (!$extractText) { $extractedText = ''; } else { $documentToText = new DocumentToText(); $documentType = $documentToText->getDocumentType($storedFilename, $contentType); /* If we're creating a file from text contents, we can skip * extracting because we already know the text contents. */ if ($fileContents !== false && $documentType == DOCUMENT_TYPE_TEXT) { $extractedText = $fileContents; } else { if ($fileContents !== false) { /* If it's not text and we are creating a file from contents, * don't try to extract text. */ $extractedText = ''; } else { if (!$fileExists) { /* Can't extract text from a file that doesn't exist. */ $extractedText = ''; } else { $documentToText->convert($tempFilename, $documentType); if ($documentToText->isError()) { $this->_isTextExtractionError = true; $this->_textExtractionError = $documentToText->getError(); $extractedText = ''; } else { $extractedText = $documentToText->getString(); } /* If we are adding a bulk resume, and parsing fails, consider it * a fatal error. */ if ($dataItemType == DATA_ITEM_BULKRESUME && $this->_isTextExtractionError) { $this->_isError = true; $this->_error = $this->_textExtractionError; return false; } } } } } $attachments = new Attachments($this->_siteID); /* We can only check for duplicates right now if the file actually * exists. We'll do it again later below. */ if ($fileExists && !$fileContents) { /* We store file size in KB, rounded to nearest KB. */ $fileSize = round(@filesize($tempFilename) / 1024); /* The md5sum is stored for duplicate checking. */ $md5sum = @md5_file($tempFilename); /* Check for duplicates. */ $duplicates = $attachments->getMatching($dataItemType, $dataItemID, $fileSize, $md5sum, $extractedText); /* Duplicate attachments are never added, but this is not a fatal * error. We will set a property to notify the caller that a * duplicate occurred. */ if (!empty($duplicates)) { $this->_duplicatesOccurred = true; if (file_exists($tempFilename)) { unlink($tempFilename); } return false; } } else { $fileSize = 0; $md5sum = ''; } /* Add the attachment record. At this point, there is no actual * associated directory / full file path. */ $attachmentID = $attachments->add($dataItemType, $dataItemID, $attachmentTitle, $originalFilename, $storedFilename, $contentType, $extractText, $extractedText, $isProfileImage, '', $fileSize, $md5sum); /* Were we successful? */ if (!$attachmentID) { $this->_isError = true; $this->_error = 'Error adding attachment to the database.'; @unlink($tempFilename); return false; } /* Store the extracted text and attachment ID in properties for later * access. */ $this->_extractedText = $extractedText; $this->_attachmentID = $attachmentID; /* Create the attachment directory. */ $uniqueDirectory = $this->_createDirectory($attachmentID, $storedFilename); if (!$uniqueDirectory) { $attachments->delete($attachmentID, false); return false; } /* Create the full path name to the file. */ $newFileFullPath = $uniqueDirectory . $storedFilename; /* Are we creating a new file from file contents, or are we moving a * temporary file? */ if ($fileContents !== false) { $status = @file_put_contents($newFileFullPath, $fileContents); if (!$status) { $this->_isError = true; $this->_error = sprintf('Cannot create file %s.', $newFileFullPath); $attachments->delete($attachmentID, false); @unlink($uniqueDirectory); return false; } /* We store file size in KB, rounded to nearest KB. */ $fileSize = round(@filesize($newFileFullPath) / 1024); /* The md5sum is stored for duplicate checking. */ $md5sum = @md5_file($newFileFullPath); /* Check for duplicates. */ $duplicates = $attachments->getMatching($dataItemType, $dataItemID, $fileSize, $md5sum, $extractedText); /* Duplicate attachments are never added, but this is not a fatal * error. We will set a property to notify the caller that a * duplicate occurred. */ if (!empty($duplicates)) { $this->_duplicatesOccurred = true; $attachments->delete($attachmentID, false); @unlink($newFileFullPath); @unlink($uniqueDirectory); return false; } } else { if ($fileExists) { /* Copy the temp file to the new path. */ if (!@copy($tempFilename, $newFileFullPath)) { $this->_isError = true; $this->_error = sprintf('Cannot copy temporary file %s to %s.', $tempFilename, $newFileFullPath); $attachments->delete($attachmentID, false); @unlink($newFileFullPath); @unlink($uniqueDirectory); return false; } /* Try to remove the temp file; if it fails it doesn't matter. */ @unlink($tempFilename); } } /* Store path to the file (inside the attachments directory) in this * object. */ $this->_newFilePath = $newFileFullPath; $this->_containingDirectory = $uniqueDirectory; /* Update the database with the new directory name. */ $attachments->setDirectoryName($attachmentID, str_replace('./attachments/', '', $uniqueDirectory)); if (!eval(Hooks::get('CREATE_ATTACHMENT_FINISHED'))) { return; } return true; }