Form Submission Attachments

Permalink 2 users found helpful
Hey Guys,

I'm having a hopefully tiny issue...

When a user submits a form with attachment (image), the e-mail delivered only shows the ID/Name of the image, instead of a download link... or even better, files as attachment..

Does anyone have a "concrete" solution for that ?.. ;)

Regards,
Masson

Massonio
View Replies: View Best Answer
Massonio replied on at Permalink Reply
Massonio
Anyone?
frz replied on at Permalink Reply
frz
Yes, the files do not show up as attachments in the email. If you follow the link to the reporting page with the form submission there should be a link to the file there.
SVijay replied on at Permalink Reply
SVijay
Hi,

It's very simple in blocks/form/controller.php you can get the FID of an image from the variable $questionAnswerPairs in line 331, get the relative path and add a parameter for link.
And alter the concrete/mail/block_form_submission.php as you want.

But when you upgrade, you will lose all the changes whatever you have altered in core coding so it would be better if you duplicate the form block and alter the block as you want.
ignician replied on at Permalink Reply
This is exactly what I'm trying to do - but I'm not much a developer. Any chance you could kindly show us how to do this?
cerulean replied on at Permalink Reply 1 Attachment
This annoyed me so much that I just had to do something about it. I can't let my client think I've provided a broken system!

I've modified two files. The file is no longer displayed as an integer in the email, but as a url e.g.http://www.mysite.com/files/5613/3241/7754/cool-icon.png...

Most email clients will turn the url into a link for you. I didn't do it because it gets flagged as spam and fails the form submission, and if this is a plain text email, you will see ugly html.

The url will get the file even if you are not logged in.

I still can't believe this has been ignored by the C5 team for so long
jordif replied on at Permalink Reply
jordif
hi cerulean!

i wanted to have a look at your solution, but the zip file seems to be broken? Could you please upload it again?

thanks!

jordi
jordif replied on at Permalink Reply
jordif
In case it might be of help to anyone else, I managed to show a download link instaed of the file ID (quite simple, thanks to SVijay instructions):

1. Copy /concrete/blocks/form/controller.php to /blocks/form/controller.php

2. Open this file and find the following code:
elseif($row['inputType']=='fileupload'){
   $answer=intval( $tmpFileIds[intval($row['msqID'])] );
}

3. Change it to:
elseif($row['inputType']=='fileupload'){
   $answer=intval( $tmpFileIds[intval($row['msqID'])] );
   $answer=BASE_URL.File::getRelativePathFromID($answer);
}
Vinylburn replied on at Permalink Reply
Vinylburn
Hi Jordif,

Okay I get it now. Line: 343,344 ,345 in the new version
BlueFractals replied on at Permalink Reply
BlueFractals
Hi jordi

I tried your solution. It's partially working. I mean it's sending the link to the email but it's not storing it in the database. Do you know a way to do both - that is email the link as well as store in the database?

I am using version 5.5.1.

Thanks
Sadu replied on at Permalink Best Answer Reply
Sadu
Hi Everyone,

My customer demanded that file uploads come through as actual attachments, but was at least happy to pay for the 2 hours it took. So here's the solution for those that have had similar frustrations.

The mail handler that comes with C5 doesn't appear to support attachments, but C5 comes with Zend mail class which does. So it's a matter of using Zend mail to send the message instead. Note that by bypassing the C5 sending function messages don't get logged like they normally would (they still show up in the form submissions list though).

Let's go.

Firstly, copy concrete/blocks/form/controller.php to blocks/form/controller.php

Comment out from approx line 397 - this is the part that sends the mail. You want to comment out this code...
/*
$mh = Loader::helper('mail');
$mh->to( $this->recipientEmail ); 
$mh->from( $formFormEmailAddress ); 
$mh->addParameter('formName', $this->surveyName);
$mh->addParameter('questionSetId', $this->questionSetId);
$mh->addParameter('questionAnswerPairs', $questionAnswerPairs); 
$mh->load('block_form_submission');
$mh->setSubject(t('%s Form Submission', $this->surveyName));
//echo $mh->body.'<br>';
@$mh->sendMail();
*/


Then add the following code to replace what you just commented out.
/* Modified code for sending which attaches files to email as attachments */
$mh = Loader::helper('mail');
$mh->addParameter('formName', $this->surveyName);
$mh->addParameter('questionSetId', $this->questionSetId);
$mh->addParameter('questionAnswerPairs', $questionAnswerPairs);
$mh->load('block_form_submission');
$zmo = $mh->getMailerObject();
$zm = $zmo['mail'];
$zm->setType(Zend_Mime::MULTIPART_RELATED);
$zm->setBodyText($mh->getBody());
$zm->setFrom($formFormEmailAddress, $formFormEmailAddress);
$recipients = explode(',', $this->recipientEmail);
foreach ($recipients as $recipient) {
$recipient = trim($recipient);
$zm->addTo($recipient, $recipient);


Doneburgers.

Note that if the core version of the controller changes at some point in the future, then you will need to re-do this process on the new controller.

Hope this helps someone out there.
primeone replied on at Permalink Reply
primeone
Thank you Sadu!
Works like a charm and solved it for me! Thanks again! :)

Cheers!
ptityop replied on at Permalink Reply
How did you manage to get this. The controller.php I have does not contain all this code but

<?php  
defined('C5_EXECUTE') or die("Access Denied.");
class FormBlockController extends Concrete5_Controller_Block_Form {}
class FormBlockStatistics extends Concrete5_Controller_Block_FormStatistics {}
class MiniSurvey extends Concrete5_Controller_Block_FormMinisurvey {}
.
Sadu replied on at Permalink Reply
Sadu
Looks like this has changed in 5.6.1

Try concrete/core/controllers/blocks/form.php from around line 444.

Cheers.
ptityop replied on at Permalink Reply
There is no line 444... ONly 5 lines of code !
Sadu replied on at Permalink Reply
Sadu
Please check the filename I gave you again - it's a different file.
ptityop replied on at Permalink Reply
oh sorry ! I try it!
ptityop replied on at Permalink Reply
worked like a charm !!! Thank you , have to keep this thread handy ... wonder why they don't just do that as default ... sounds so natural ..
Pomlo replied on at Permalink Reply
Pomlo
Hi,

I've implemented Sadu's solution in form.php (running 5.6.0.1) and it does not seem to work for me.

When I add entries in the log, I can trace the filename and the recipient are ok but the email just seem to not be sent. No entry in the log for email sending and nothing in my mailbox.

Any idea where to investigate ?

ps the mail sending is working with the original method it's not a mail server/mail box problem.
Pomlo replied on at Permalink Reply
Pomlo
Hi,

I finally found the issues in the code above from Sadu.

1) it will not work if you use SMTP email and not the php mail()

To fix this, you need to retrieve the "transport" from the mail object and pass it to the send method

//$zm->send(); //Replace the send command line
$tr = (isset($zmo['transport'])) ? $zmo['transport'] : NULL;
$zm->send($tr);


2) it will still not work if you use smtp auth as the formFormEmailAddress var is empty in my case (using 6.0.1)

You'll need to add before the initial mail sending command a fallback

...
}else{
  $adminUserInfo=UserInfo::getByID(USER_SUPER_ID);
  $formFormEmailAddress = $adminUserInfo->getUserEmail();
}
// Fall back on default email
if (!isset($formFormEmailAddress)) {
  $formFormEmailAddress = EMAIL_DEFAULT_FROM_ADDRESS;
}
/*
$mh = Loader::helper('mail');
$mh->to( $this->recipientEmail );
...


It's now working for me but in my opinion, this is a poor implementation (but very useful Sadu, very grateful you put us on track ;) ) as we can't benefit from the mail helper implementation. The email default fall back is managed there, the logging, the transport, ...

I should shortly add a couple of methods to the mail helper and review this code if it makes sense to anyone.

Hope this helps
Pomlo replied on at Permalink Reply
Pomlo
Hi again,

As described in the previous post, I've performed the modifications in the the mail helper as I believe it's a more clean way to do.

In the file : concrete/core/helper/mail.php

1) add a class member (around line 31) for attachements

...
protected $bodyHTML = false;
protected $attachments = array();


2) add the method to add the attachments (around line 290, above the Send method)

/**
    * Adds file attachment to the email.
    * @param File file
    * @return void
    */
   public function addAttachment(File $file) {
      $fh = Loader::helper('file');
      $mh = Loader::helper('mime');
      $fileName = $file->getFilename();
      $fileExt = $fh->getExtension($file->getPath());
      $contents = $fh->getContents($file->getPath());
      if (!contents) {
         throw new Exception(t('Unable to get the file contents for attachment.'));
      }
      Loader::library('3rdparty/Zend/Mime/Part');


3) Update the send method (around line 377, just before the (try block to send the email)

if(is_array($this->attachments) && count($this->attachments)) {
            $mail->setType(Zend_Mime::MULTIPART_RELATED);
            foreach($this->attachments as $attachment) {
               $mail->addAttachment($attachment);
            }
         }
         try {
            $mail->send($transport);
...


4) at the end of the send method, update the Reset block to clear attachments (around line 435)

...
         $this->bodyHTML = '';
         $this->attachments = array();
      }


That's it for the Mail helper, now get back the the original file concrete/code/controllers/blocks/form.php

1) Insert the from files using the mail helper (around line 451)
...
            $mh->setSubject(t('%s Form Submission', $this->surveyName));
            foreach( $rows as $row ){
               if ($row['inputType'] == 'fileupload') {
                  $fileId = intval( $tmpFileIds[intval($row['msqID'])] );
                  if ($fileId) {
                     $mh->addAttachment(File::getByID($fileId));
                  }
               }
            }
            //echo $mh->body.'<br>';
...


Hope this helps
leertes replied on at Permalink Reply
leertes
Small amendment to this as the 'file not found' it still happens in the dash reports.

Use the work above to store the url in the db and then use the code below to show the filename in the reports.


in(5.3.6.1) concrete\single_pages\dashboard\reports\forms.php

around line 195

<?php foreach($questions as $questionId => $question):
if ($question['inputType'] == 'fileupload') {

$fidurl = $text->entities($answerSet['answers'][$questionId]['answer']);
$formFileid = substr( $fidurl, strrpos( $fidurl, '/' )+1 );
echo '<td>'.$formFileid.'</td>';


} else if($question['inputType'] == 'text') {
echo '<td>'.$text->entities($answerSet['answers'][$questionId]['answerLong']).'</td>';
} else {
echo '<td>'.$text->entities($answerSet['answers'][$questionId]['answer']).'</td>';
}

endforeach?>
leertes replied on at Permalink Reply
leertes
Excel export bonus!!!

in(5.6.3.1) concrete\core\controllers\single_pages\dashboard\reports\forms.php

around line109

Changed to add file to Excel export - but - I have knocked out File not Found

}elseif($question['inputType']=='fileupload'){
echo "\t\t<td>\r\n";

$fidurl = $answerSet['answers'][$questionId]['answer'];
$formFileid = substr( $fidurl, strrpos( $fidurl, '/' )+1 );
// echo '<p>'.$formFileid.'</p>';

$fID=intval($answerSet['answers'][$questionId]['answer']);
$file=File::getByID($fID);
if($fID && $file){
$fileVersion=$file->getApprovedVersion();
echo "\t\t\t".'<a href="'. $fileVersion->getDownloadURL() .'">'.$fileVersion->getFileName().'</a>'."\r\n";
}else{
echo "\t\t\t".'<a href="'. $fidurl .'">'.$formFileid.'</a>'."\r\n";
}
echo "\t\t</td>\r\n";
}else{
echo "\t\t<td>\r\n";
echo "\t\t\t".$answerSet['answers'][$questionId]['answer'].$answerSet['answers'][$questionId]['answerLong']."\r\n";
echo "\t\t</td>\r\n";
}
}
echo "\t</tr>\r\n";