I'm looking to write a module that automatically uploads the submissions of a webform to an ftp server every week or so.

I'm looking for the recommended way to use the CSV export plugin that comes with the WebForm module to render a csv file to a string. I would want to set the following options:

  • separator (default is , but should be ; because Europe)
  • start date and end date of submissions (weekly export)

I see there are a lot of classes and configuration options available, but I'm not sure about the best way to string them together to achieve what I need.

  • Right now, the best solution is to use drush webform-export to generate the CSV and then call a custom drush command to upload the file to an FTP server. The challenge with programmatically generating a CSV is that the WebformSubmissionExporter services uses batch processing which can be difficult to programmatically trigger.
    – jrockowitz
    Commented Mar 8, 2018 at 10:43
  • You could try using Views Data Export which should take care of both of your bullet points.
    – No Sssweat
    Commented Mar 8, 2018 at 10:58
  • @NoSssweat : I've considered it. The integration between Webform submissions and Views is still a little awkward though. I'm likely to have to expand this to more webforms in the future, so I'd have to make a View for each webform. Plus I would need to use webform_views which is currently only in alpha release. Commented Mar 8, 2018 at 12:53
  • @jrockowitz : can you point me to potential pitfalls in the code I posted? Webform is largely your work, so I expect you know best. Commented Mar 8, 2018 at 14:27

3 Answers 3


After looking at the drush webform-export code I came up with the following code sample. It appears to work, however jrockowitz advises me that using drush straight up should be the best solution. I'm sure there's something wrong with the following code. For one, it probably breaks when the export is too large.

$webform_id = 'easykit_vip_formulier';
$webform = \Drupal\webform\Entity\Webform::load($webform_id);
$submission_exporter = \Drupal::service('webform_submission.exporter');
$export_options = $submission_exporter->getDefaultExportOptions();

$export_options['delimiter'] = ';';
$export_options['multiple_delimiter'] = ',';
$export_options['range_type'] = 'date';
$export_options['range_start'] = '2018-02-18';
$export_options['range_end'] = '2018-02-26';

$file_path = $submission_exporter->getExportFilePath();

print file_get_contents($file_path);


In-case if anyone interested in a custom script, check this out:


namespace Drupal\mymodule\Controller;
use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\HttpFoundation\Response;

class DownloadCSVController extends ControllerBase{

    public function downloadCustomers(){

        $submissions = array();
        $row = array();
        $select = \Drupal::service('database')
        ->select('webform_submission_data', 'wsd')
        ->fields('wsd', array('sid'))
        ->orderBy('wsd.sid', 'DESC')
        ->condition('wsd.webform_id', 'webform_name', '=')

        // Get all the results.
        $results = $select->fetchAll(\PDO::FETCH_COLUMN);
        if ($results != null && count($results) >= 1) {
            $storage = \Drupal::entityTypeManager()->getStorage('webform_submission');
            $submissions = $storage->loadMultiple($results);


        if(count($submissions) > 0) foreach ($submissions as $submission) {
            $data = array(

            $rows[] = implode(',', $data);

        $content = implode("\n", $rows);
        $response = new Response($content);
        $response->headers->set('Content-Type', 'text/csv');
        $response->headers->set('Content-Disposition','attachment; filename="sample.csv"');

        return $response;



  path: '/mymodule/downloadCustomers'
    _title: 'Download Customers'
    _controller: \Drupal\mymodule\Controller\DownloadCSVController::downloadCustomers
    _permission: 'access content'

Better to create a service so you can use it anywhere:


namespace Drupal\my_module\Services;

use Drupal\Core\Archiver\ArchiverManager;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\Database\Query\SelectInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
use Drupal\webform\Entity\WebformSubmission;
use Drupal\webform\Plugin\WebformElementManagerInterface;
use Drupal\webform\Plugin\WebformExporterManagerInterface;
use Drupal\webform\WebformSubmissionExporter;
use Drupal\webform\WebformSubmissionForm;
use Drupal\Core\Logger\LoggerChannelFactory;
use Drupal\Core\Entity\EntityTypeManagerInterface;
use Drupal\Component\Utility\Crypt;
use Drupal\Component\Serialization\Json;
use Drupal\Core\Database\Connection;
use PDO;

 * Class DailySubmissionCSVExport.
class DailySubmissionCSVExport extends WebformSubmissionExporter

  protected $connection;

   * {@inheritDoc}
  public function __construct(
    ConfigFactoryInterface $config_factory,
    FileSystemInterface $file_system,
    EntityTypeManagerInterface $entity_type_manager,
    StreamWrapperManagerInterface $stream_wrapper_manager,
    ArchiverManager $archiver_manager,
    WebformElementManagerInterface $element_manager,
    WebformExporterManagerInterface $exporter_manager,
    Connection $connection
    parent::__construct($config_factory, $file_system, $entity_type_manager, $stream_wrapper_manager, $archiver_manager, $element_manager, $exporter_manager);
    $this->connection = $connection;

   * {@inheritdoc}
  public function generate()
    $entity_ids = $this->getQuery()->execute()->fetchAll(PDO::FETCH_COLUMN, 'sid');
    $webform_submissions = WebformSubmission::loadMultiple($entity_ids);


   * {@inheritdoc}
  public function getQuery()
    $webform = $this->getWebform();

    /** @var SelectInterface $query * */
    $query = $this->connection->select('webform_submission_data', 'wsd');
    $query->join('webform_submission', 'ws', 'wsd.sid = ws.sid');
    $query->fields('wsd', array('sid'));
    $query->orderBy('wsd.sid', 'DESC');
    return $query;

Define service in my_module.service.yml file

    class: Drupal\my_module\Services\DailySubmissionCSVExport
    arguments: ['@config.factory', '@file_system', '@entity_type.manager', '@stream_wrapper_manager', '@plugin.manager.archiver', '@plugin.manager.webform.element', '@plugin.manager.webform.exporter', '@logger.factory', '@database']

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.