Save file to alternate location

April 16th, 2013 Leave a comment Go to comments

Common issue: the plugin saves files that are submitted via forms to the database…but I want to save the file to a special directory.

To do this, you create a filter as described on the page about Changing Form Data Before it is Saved but you use the following code.

Thanks to a user for providing example code.

Change the values of $formName, $fieldName and $uploaddir to suite your needs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
function cfdbFilterSaveFile($formData)
{
    // CHANGE THIS: CF7 form name you want to manipulate
    $formName = 'your-form'; 
 
    // CHANGE THIS: upload field name on your form
    $fieldName = 'form-file'; 
 
    // CHANGE THIS: directory where the file will be saved permanently
    $uploaddir = '/root/htdocs/wp-content/uploads/path/to/save/dir/';
 
    if ($formData && $formName == $formData->title) {
        // make a copy of data from cf7
        $formCopy = clone $formData;
 
        // breakdown parts of uploaded file, to get basename
        $path = pathinfo($formCopy->uploaded_files[$fieldName]);
        // directory of the new file
        $newfile = $uploaddir . $path['basename'];
 
        // check if a file with the same name exists in the directory
        if (file_exists($newfile)) {
            $dupname = true;
            $i = 2;
            while ($dupname) {
                $newpath = pathinfo($newfile);
                $newfile = $uploaddir . $newpath['filename'] . '-' . $i . '.' . $newpath['extension'];
                if (file_exists($newfile)) {
                    $i++;
                } else {
                    $dupname = false;
                }
            }
        }
 
        // make a copy of file to new directory
        copy($formCopy->uploaded_files[$fieldName], $newfile);
        // save the path to the copied file to the cfdb database
        $formCopy->posted_data[$fieldName] = $newfile;
 
        // delete the original file from $formCopy
        unset($formCopy->uploaded_files[$fieldName]);
 
        return $formCopy;
    }
    return $formData;
}
 
add_filter('cfdb_form_data', 'cfdbFilterSaveFile');
  1. brian
    February 6th, 2013 at 13:45 | #1

    Hi,
    I tried using the code above replacing $formName and $uploaddir but it cannot seem to get files to upload into the directory. I’ve tried different variation on the directory path but nothing seems to work. The files are still posted to the database. Any suggestions would be greatly appreciated.

    Cheers,
    Brian

  2. sebi
    March 12th, 2013 at 20:27 | #3

    Hi

    I got this part working, but having troubles showing the records in the admin.
    In the tables of the admin it links only the files stored in the db for download.

    Is there any config or easy way to show download links in the admin for files stored in the filesystem as well?

    Cheers, Sebi

    • Michael Simpson
      March 13th, 2013 at 11:39 | #4

      In the code above, I would set a new field to point to the uploaded file. After:
      $formCopy->posted_data['form-file'] = $newfile;
      I would add something like
      $formCopy->posted_data['file-url'] = "http://your-site.com/path/to/$newfile";

  3. Shuki
    April 16th, 2013 at 10:55 | #5

    Please remove above message, it was a mistake.

    I am getting this message

    PHP Warning: copy(): Filename cannot be empty in /html/wp-content/themes/xxx/functions.php on line 406

    And the file is nowhere to be found.

    Thanks in advance,
    Shuki

    • Michael Simpson
      April 16th, 2013 at 14:17 | #6

      I think the issue is you need to change ‘form-file’ to the name of the form field on your form. I’ll update that in the code example on this page.

  4. r1987
    May 7th, 2013 at 10:29 | #7

    Hello,

    This snippet seems to not work in my situation also.

    Some friendly observations using Contact Form 7:

    -Email is sent out and it will be saved to the db, but on the front-end after submiting the sending proccess freezes (ajax-gif circles forever).
    -File is not saved to the specified folder.
    -In DB extension, attachment field shows the path of the file, but its not clickable and its not on ftp also.

    Im running on WordPress 3.5.1, clean install, twentytwelve theme.

    It would be really cool to get this snippet working somehow…

    • Michael Simpson
      May 7th, 2013 at 10:51 | #8

      Check if it is throwing an exception. Wrap all the code inside the function in a try-catch and print to your error log.

      1
      2
      3
      4
      5
      6
      7
      8
      
      function cfdbFilterSaveFile($formData) {
          try {
              // ... code
          }
          catch (Exception $ex) {
              error_log($ex->getMessage());
          }
      }

      PS. Will need your php.ini file to have
      error_log = /path/to/a/file/errors.txt

  5. r1987
    May 7th, 2013 at 11:57 | #9

    @Michael Simpson

    Tried this, created the php.ini file and errors.txt file. errors.txt file is empty after I submit the form.

    But I checked the WP error_log, and there was this line:
    [07-May-2013 15:51:46 UTC] PHP Warning: copy(/public_html/wordpress/wp-content/uploads/pictures/Picture-1.png) [function.copy]: failed to open stream: No such file or directory in /home/rannoait/public_html/wordpress/wp-content/themes/twentytwelve/functions.php on line 488

    Any help?

  6. Michael Simpson
    May 7th, 2013 at 12:05 | #10

    @r1987
    Does /public_html/wordpress/wp-content/uploads/pictures/ exist and is it writeable?

  7. r1987
    May 7th, 2013 at 12:27 | #11

    @Michael Simpson

    Yes, it exsists and its writable.

  8. Michael Simpson
    May 8th, 2013 at 22:06 | #12

    @r1987
    If the copy line does not work, you could try this as an alterative and see if you get an error with more information

    1
    2
    3
    4
    5
    
            $fsrc = fopen($formCopy->uploaded_files[$fieldName],'r'); 
            $fdest = fopen($newfile,'w+'); 
            stream_copy_to_stream($fsrc,$fdest); 
            fclose($fsrc); 
            fclose($fdest);

    PS, be sure the directory is writeable by the user that the web server runs as (like “apache”).

  9. r1987
    May 9th, 2013 at 07:00 | #13

    Well, Michael. I have to appologize because of my dumbness.

    What I did:
    -I copied the path location from my FTP and it was /public_html/…
    -I watched the error_log again now, and noticed, it showed /home/mydomainname/public_html/…

    And I got the very first code working, it was the wrong path all the time.

    Sorry for waisting your time. May-be it would be good to really make it red, that people some how copy the “real” root.

    But there’s one more question that I have:

    Lets say, that I have two forms with the upload field and I want both form uploads to go to the same folder, then I just copy/paste the same filter with just the new form name and field name right?

    • Michael Simpson
      May 9th, 2013 at 08:46 | #14

      Regarding having two forms, I would try not to duplicate the code. Instead I would parameterize the function we have and create wrapper functions for each form submission. In other words, the following:

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      72
      73
      
      // Added parameters to this function
      function cfdbFilterSaveFile($formData, $formName, $fieldName, $uploaddir)
      {
          if ($formData && $formName == $formData->title) {
              // make a copy of data from cf7
              $formCopy = clone $formData;
       
              // breakdown parts of uploaded file, to get basename
              $path = pathinfo($formCopy->uploaded_files[$fieldName]);
              // directory of the new file
              $newfile = $uploaddir . $path['basename'];
       
              // check if a file with the same name exists in the directory
              if (file_exists($newfile)) {
                  $dupname = true;
                  $i = 2;
                  while ($dupname) {
                      $newpath = pathinfo($newfile);
                      $newfile = $uploaddir . $newpath['filename'] . '-' . $i . '.' . $newpath['extension'];
                      if (file_exists($newfile)) {
                          $i++;
                      } else {
                          $dupname = false;
                      }
                  }
              }
       
              // make a copy of file to new directory
              copy($formCopy->uploaded_files[$fieldName], $newfile);
              // save the path to the copied file to the cfdb database
              $formCopy->posted_data[$fieldName] = $newfile;
       
              // delete the original file from $formCopy
              unset($formCopy->uploaded_files[$fieldName]);
       
              return $formCopy;
          }
          return $formData;
      }
       
      // Wrapper function for form1 to be registered as a filter
      function form1_save_file($formData)
      {
          // CHANGE THIS: CF7 form name you want to manipulate
          $formName = 'form1';
       
          // CHANGE THIS: upload field name on your form
          $fieldName = 'form-file';
       
          // CHANGE THIS: directory where the file will be saved permanently
          $uploaddir = '/root/htdocs/wp-content/uploads/path/to/save/dir/';
       
          cfdbFilterSaveFile($formData, $formName, $fieldName, $uploaddir);
      }
       
      // Wrapper function for form2 to be registered as a filter
      function form2_save_file($formData)
      {
          // CHANGE THIS: CF7 form name you want to manipulate
          $formName = 'form2';
       
          // CHANGE THIS: upload field name on your form
          $fieldName = 'form-file';
       
          // CHANGE THIS: directory where the file will be saved permanently
          $uploaddir = '/root/htdocs/wp-content/uploads/path/to/save/dir/';
       
          cfdbFilterSaveFile($formData, $formName, $fieldName, $uploaddir);
      }
       
      // Register wrapper functions
      add_filter('cfdb_form_data', 'form1_save_file');
      add_filter('cfdb_form_data', 'form2_save_file');
  1. No trackbacks yet.
You must be logged in to post a comment.