Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

File upload #40

Closed
dmncls opened this issue May 15, 2015 · 14 comments
Closed

File upload #40

dmncls opened this issue May 15, 2015 · 14 comments

Comments

@dmncls
Copy link

dmncls commented May 15, 2015

Hi there,

I am using CF7 with this plugin and it is great for posting to our backend jobs server.

I was wondering how I can get a file upload to be sent as well.

Any ideas?

Cheers,
Dominic

@ghost
Copy link

ghost commented Jul 3, 2015

I'm trying to get this working as well. Does the fact that this question is posted and has not been asnwered yet, mean that this is currently not possible??

Because that would be a big no-go for me...

@dmncls
Copy link
Author

dmncls commented Jul 4, 2015

Well I actually wrote a custom filters and it was a bit of pain.

In my case I was posting to the localhost of the same server so I used a plugin filter to make a temporary copy of the uploaded file, and then I added an extra POST argument with the location of the file. This only worked or me because my localhost website can pick up the file locally.

I did try to attach it using POST but I had some trouble, but it may have been because I was using the wrong uploaded file location. The right one to use is WPCF7_Submission::uploaded_files().

This is my work-in-progress version:

add_filter( 'Forms3rdPartyIntegration_service_filter_args', 'forms3rdparty_add_files', 10, 3 );
function forms3rdparty_add_files( $post_args, $service, $form ) {
        $post_args['body']['files'] =var_export($_FILES,true);
        foreach ( $_FILES as $ref => $info ) {
                if ( !empty( $info['error'] ) ) {
                        continue;
                }
                if ( isset( $post_args['body']['UPLOAD_' . $ref] ) ) {

                        $submission = WPCF7_Submission::get_instance();
                        $uploaded_files = $submission->uploaded_files();

                        if ( isset($uploaded_files[$ref]) ) {
                                $new_filename = tempnam( sys_get_temp_dir(), 'forms3rdparty-').'-'.basename($uploaded_files[$ref]);
                                copy($uploaded_files[$ref], $new_filename);
                                $post_args['body']['UPLOAD_' . $ref] = '@'.$new_filename;
                        }
                }
        }
        return $post_args;
}

@ghost
Copy link

ghost commented Jul 5, 2015

Hi Dominic,

Sound great!

Unfortunately for me I'm using Gravity forms, so I will need to deep dive into this to be able to adapt your POST version as it seems you are using Contact Form 7. Why do you call this a work in progress version, which solution do you then currently use to accomplish this?

Regards,

@dmncls
Copy link
Author

dmncls commented Jul 6, 2015

Well I call it a 'work in progress' version because I would like to actually find a way to forward the uploaded files to the 3rd party site, even if it is on the same server. At the moment this code is working although I want to make it into a little plugin and fix it so it works as originally intended. At the moment it is just a workaround.

Also, just so you know, in the code I posted I have used the prefix 'UPLOAD_'. This is because I have used this prefix for the name attribute on any upload file fields when I created my CF7 form.

To adjust the code for Gravity Forms I would take some pieces from here:
https://www.gravityhelp.com/documentation/article/gform_notification/#5-attach-single-file-uploads
... especially how to get the locations of the uploaded files.

Cheers,

@zaus
Copy link
Owner

zaus commented Jul 6, 2015

Sorry I didn't have a chance to help you out more, but nice work @dominiceales. The hard part is extracting the file from the form submission, and as you've shown it's specific to each form plugin. You could also hook to ..._get_submission to handle that part, so then it's available to the 'rest' of my plugin (as a mapping field, etc).

Copying out the relevant GF stuff from the link above, in case it's not available:

$fileupload_fields = GFCommon::get_fields_by_type( $form, array( 'fileupload' ) );
if(!is_array($fileupload_fields)) return; // nothing to upload
$upload_root = RGFormsModel::get_upload_root();
foreach( $fileupload_fields as $field ) {
        $url = $entry[ $field['id'] ];
        $attachment = preg_replace( '|^(.*?)/gravity_forms/|', $upload_root, $url );
// etc

I noticed you're using the cURL-specific trick of prepending the filepath with @, which I'm guessing works when wp_remote_post uses cURL underneath. I've seen some posts mentioning it not working, so just wanted to point out that trick in case it catches anyone.

Some alternatives I found for attaching:

@dmncls
Copy link
Author

dmncls commented Jul 6, 2015

@zaus
Actually you are right - the @ trick with cURL didn't work at all. It just stayed in my code because I didn't take it out. cURL is not uploading the file at all using the @, instead my receiving script strips the @ and opens the local file (since I am posting to the same server).

I like the idea of using ...get_submission and sending as multipart. My forms are more complex than only one uploaded file, so sending as binary isn't suitable.

Would this be something you would consider adding to your plugin? If not would you recommend making a separate, dependent plugin or sending through a PR to this repo?

@zaus
Copy link
Owner

zaus commented Jul 6, 2015

@dominiceales good to know your "custom workaround" re: @. I think this kind of functionality would be best as a separate 'add-on' plugin, since the majority of users don't need file uploads (at least, they're not vocal about it). The other problem with core functionality is that it has to support the 3 forms plugins (CF7, GF, Ninja Forms) which can make it harder to write, whereas an add-on can be as specific as you want. I "try" to keep the base plugin lean(er) but extensible with hooks, so that it's easy to enhance the functionality through other plugins. If you write something I'd be happy to link to it, and if you find that you need more hooks (such as form-specific submission alteration) I could probably handle a PR to add them.

@ghost
Copy link

ghost commented Jul 31, 2015

@zaus: I would love to have this functionality for my website, but don't have the knowledge to do it myself. Would you therefore be available to code this for me? Together with 2 or 3 smaller modifications to the standard version and the issue I'm currently having for getting this up-and-running (as just posted on Wordpress.com). And of course with the result as open source...

If interested please let me know, so we can discuss this further!

Regards,

@dmncls
Copy link
Author

dmncls commented Aug 11, 2015

@zaus I have a working version of my extension plugin for CF7 (and probably Gravity forms too based on your code).

There are two things I would need added to your plugin:

  1. A way to include the uploaded files ($_FILES or equivalent) in your $submission array, like here, here and here
  2. Addition of the $submission variable to the apply_filter for service_post_args

Requirement 1 above could be done with a plugin specific filter as you suggested but I think this would mean too much fiddling around for people using the plugin. I would prefer if the uploaded files were always included in the $submission. I have an implementation for CF7 and GF, but it looks like access to upload data with NF is a paid extension.

Let me know your thoughts on this. (I can post the plugin code if you like.)

@dmncls
Copy link
Author

dmncls commented Aug 12, 2015

@zaus I thought I'd share a bit more. I have added my plugin here
dmncls/forms-3rdparty-integration-upload@031ec3e

Here is the patch file for your repo so you can see what I have done to get it to work.

diff --git a/forms-3rdparty-integration.php b/forms-3rdparty-integration.php
index 15dc9f4..ef3ef52 100644
--- a/forms-3rdparty-integration.php
+++ b/forms-3rdparty-integration.php
@@ -493,6 +493,7 @@ class Forms3rdPartyIntegration {
                    )
                , $service
                , $form
+               , $submission
            );

            //remote call
diff --git a/plugins/contactform7.php b/plugins/contactform7.php
index 68b00cf..4f42c88 100644
--- a/plugins/contactform7.php
+++ b/plugins/contactform7.php
@@ -77,7 +77,10 @@ class Forms3rdpartyIntegration_CF7 extends Forms3rdpartyIntegration_FPLUGIN {
     */
    protected function GET_FORM_SUBMISSION($form) {
        $submission = WPCF7_Submission::get_instance();
-       if($submission) return $submission->get_posted_data();
+       if($submission) {
+           return $submission->get_posted_data() 
+               + array('FILES'=>$submission->uploaded_files());
+        }
        return array('no submission');
    }

diff --git a/plugins/gravityforms.php b/plugins/gravityforms.php
index 9343d87..6a1e64c 100644
--- a/plugins/gravityforms.php
+++ b/plugins/gravityforms.php
@@ -74,7 +74,8 @@ class Forms3rdpartyIntegration_Gf extends Forms3rdpartyIntegration_FPLUGIN {
     * Get the posted data from the form (or POST, wherever it is)
     */
    protected function GET_FORM_SUBMISSION($form) {
-       return stripslashes_deep($_POST); // fix issue #42
+       return stripslashes_deep($_POST) // fix issue #42 
+         + array('FILES'=>$_FILES); 
    }

    /**

@zaus
Copy link
Owner

zaus commented Aug 14, 2015

Rather than modifying plugin code to include the files (which is what I was trying to avoid) did you try a later hook to ...get_submission?

And instead of trying to roll support for all the Form Plugins, you can keep 'em separate (and as you mention Ninja needs to be separate anyway since it relies on paid stuff?).

Something like the following should attach the files to the $post array, at which point it'd still be available to all of the mappings etc downstream.

abstract class F3i_Files_Base {
    function __construct() {
        // expose files through submission $post array -- makes it available to mappings
        add_filter(Forms3rdPartyIntegration::$instance->N('get_submission'), array(&$this, 'get_submission'), 11, 2);

        // if you don't want user to need to actually type in the mapping
        add_filter(Forms3rdPartyIntegration::$instance->N('service_filter_post'), array(&$this, 'automap'), 11, 5);

        $this->_file_entry = 'FILES'; // or get from a configurable wp_option?
    }

    private $_file_entry; // alias to where we stick it in the submission/post array

    public function get_submission($submission, $form) {
        return $submission + array($this->_file_entry=>$this->get_files()); 
    }

    abstract protected function get_files();

    public function automap($post, $service, $form, $sid, $submission) {
        $post[$this->_file_entry] = $submission[$this->_file_entry];
    }
}

/** plugin -- active if using GF **/
public class F3i_GF_Files : F3i_Files_Base {
    protected function get_files() {
        return $_FILES;
    }
}


/** plugin -- active if using CF7 **/
public class F3i_CF7_Files : F3i_Files_Base {
    protected function get_files() {
        $cf7 = WPCF7_Submission::get_instance();
        return $cf7 ? $cf7->uploaded_files() : array();
    }
}

Do you need the original submission in apply_filter for service_filter_args? Because you've made it available to the mapping you should be able to pass it along like the other submission fields, in which case it'd be part of $post_args['body']. I added an extra hook to automap it without needing a user entry.

For that matter, you can do the above file inclusion directly on $post_args['body'] in the service_filter_args hook since $form is available in that filter (and neither CF7 nor GF actually reference their form object to get the submission data).

@dmncls
Copy link
Author

dmncls commented Aug 14, 2015

@zaus good points. I'll have a look at doing something like this.

@zaus
Copy link
Owner

zaus commented Aug 14, 2015

Closing, not to say this isn't a valid discussion but that it's not something for the core plugin. Please follow up here, I'm pretty sure I'll still get emails about it...

@zaus zaus closed this as completed Aug 14, 2015
zaus added a commit to zaus/forms-3rdparty-files that referenced this issue Oct 8, 2015
@MakarkinPRO
Copy link

MakarkinPRO commented Jun 5, 2017

Does it's working with Contact Form 7? Looks like everytime I fill the form the ConactForm7 delete all file into my server after sending by email. How to solve it?

I found solution of commenting
//$this->remove_uploaded_files();
at submission.php file

but after next Contact Form 7 update I need to comment it again? how to solve it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants