Jump to content

Download all files as ZIP from inputfield file?


dragan
 Share

Recommended Posts

In page-edit mode, it would be nice to have an optional download-button for inputfield type file.

i.e. when a user has uploaded two dozen files (perhaps through the frontend), and someone else needs to download these from the backend all at once, without having to open an FTP client. There would simply be a download link / button, and a ZIP would be generated on the fly, containing all files.

If someone has an idea how to do that (a hook?), I'd be all ears :D

  • Like 1
Link to comment
Share on other sites

Here are some starters:

  • Hook into InputfieldFile::render method to add (modify $event->return and concatenate html string) an anchor link with its href set to a custom template/PHP file where you build your own zip file.
    (Preferentially, add a form with a download button and a hidden field for current page id etc and set its action attribute to the template file)
  • Inside the template file, you'll get the page id from $input->post then build your zip file
  • foreach($page->files_field as $name => $file) {
        $filePath = $file->path
        // ...
    }
    Use $files->zip() method to zip multiple files
    https://processwire.com/api/ref/files/zip/

    or (from /wire/core/WireFileTools.php)
     
    // Create zip of all files in directory $dir to file $zip
    $dir = $config->paths->cache . "my-files/"; 
    $zip = $config->paths->cache . "my-file.zip";
    $result = $files->zip($zip, $dir); 
     
    echo "<h3>These files were added to the ZIP:</h3>";
    foreach($result['files'] as $file) {
      echo "<li>" $sanitizer->entities($file) . "</li>";
    }
    
    if(count($result['errors'])) {
      echo "<h3>There were errors:</h3>";
      foreach($result['errors'] as $error) {
        echo "<li>" . $sanitizer->entities($error) . "</li>";
      }
    }
    and build your zip file
  • Once the zip file is built force browser to download
    https://stackoverflow.com/a/1628281

If you have any questions, ask away

  • Like 5
Link to comment
Share on other sites

Have done this for image fields, it adds a button to the end of the inputfield, code below. Checks for ZipArchive class before installing. Now that I read the code it should work for files but haven't tested! It's got configuration options too, to enable per field basis, either way should it should be super quick to edit if something is not working.

<?php

class ExportFieldImages extends WireData implements Module, ConfigurableModule {
    
    static public function getDefaultConfig() {
        return array(
            "includeFields" => ''
        );
    }

    public static function install(){
        $session = wire("session");
        if(!class_exists('\ZipArchive')){
            throw new WireException("ZipArchive is required to create the zip file");
        }
    }
    
    public static function getModuleInfo() {
        return array(
            'title' => 'ExportFieldImages',
            'version' => 0.1, 
            'summary' => "Adds a button bellow images field to download a zip containing files.",
            'author' => 'Eduardo San Miguel Garcia',
            'singular' => true,
            'href' => '',
            'autoload' => true
        );
    }

    public function init() {
        $this->addHookAfter('InputfieldImage::render', $this, 'afterInputfieldImageRender');
        $this->addHookAfter("ProcessPageEdit::execute", $this, "pageEditExecuteBefore");
    }

    public function pageEditExecuteBefore(HookEvent $event){
        $session = wire("session");
        $input = wire("input");
        $page = wire('pages')->get($input->get->id);
        $name = $page->name;
        $zip = $config->paths->cache . "${$name}.zip";
        
        if($input->get->downloadImages == "true"){
            wire("log")->save("custom", "excecuted page edit!");
            $array = wire('files')->zip($zip,
                                        $page->get($input->get->field)->explode("filename"),
                                        array("overwrite" => true)  );
            if(!empty($array["errors"])){
                foreach($array["errors"] as $error){
                    $this->error($error);
                }
                return;
            } else{
                header('Content-Type: application/zip');
                header("Content-Disposition: attachment; filename='{$name}.zip'");
                echo readfile($zip);
                return $this->halt();
            }
            
        }
    }
    
    public function afterInputfieldImageRender(HookEvent $event){
        $field = $event->object;
        $input = wire("input");
        $configData = wire('modules')->getModuleConfigData($this);
      
        $out = $event->return;
        
        if(in_array( $field->name, $configData['includeFields'])){

            $button = wire('modules')->get('InputfieldButton');
            $button->class = $button->class . " ExportFieldImages";
            $button->icon = 'download';
            $button->href = "./?downloadImages=true&field={$field->name}&id={$input->get->id}";
            $button->value = "Download Files";
            $btn .= "<span style='display:block; position:relative; float:right;' class='InputfieldPageTableButtons'>" . $button->render() . "</span>";
            $out .= $btn;
        }
        
        $event->return = $out;
        
    }
    
    public function getModuleConfigInputfields(array $data){
        $modules = wire("modules");
        $fields = wire('fields');
        
        $defaults = self::getDefaultConfig();
		$data = array_merge($defaults, $data);
        
        $form = new InputfieldWrapper();
        
        $field = $modules->get("InputfieldAsmSelect");
		$field->name = "includeFields";
		$field->label = __("Fields to enable download button");
		$field->description = __("Choose the image fields where download button should appear");
        foreach($fields as $f){
            if($f->flags & Field::flagSystem) continue;
            if($f->type == "FieldtypeImage" || $f->type == "FieldtypeFile"){
                $field->addOption($f->name);
            }
        }
		$field->value = $data['includeFields'];
		
		$form->add($field);
        return $form;
    }
    
}

 

  • Like 4
Link to comment
Share on other sites

  • 2 years later...

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

×
×
  • Create New...