spivurno
5/6/2014 - 2:49 PM

Gravity Wiz // Gravity Forms // Zip Uploaded Files

Gravity Wiz // Gravity Forms // Zip Uploaded Files

<?php
/**
 * WARNING! THIS SNIPPET MAY BE OUTDATED.
 * The latest version of this snippet can be found in the Gravity Wiz Snippet Library:
 * https://github.com/gravitywiz/snippet-library/blob/master/gravity-forms/gw-zip-files.php
 */
/**
* Gravity Wiz // Gravity Forms // Zip Uploaded Files
*
* Needs description.
*
* @version	 1.1
* @author    David Smith <david@gravitywiz.com>
* @license   GPL-2.0+
* @link      http://gravitywiz.com/...
*/
class GW_Zip_Files {

    /**
     * @todo
     *     + add support for auto-attaching to notification
     *     + add support for multiple zip files per form (by field)
     *     + add support for removing file fields from {all_fields}
     *     + add support for linking to specific zip by 'zip_name': {gwzip:zip_name}
     */

    public function __construct( $args = array() ) {

        // make sure we're running the required minimum version of Gravity Forms
        if( ! property_exists( 'GFCommon', 'version' ) || ! version_compare( GFCommon::$version, '1.8', '>=' ) )
            return;

        // ZipArchive must be installed for PHP
        if( ! class_exists( 'ZipArchive' ) )
            return;

        // set our default arguments, parse against the provided arguments, and store for use throughout the class
        $this->_args = wp_parse_args( $args, array(
            'form_id'   => false,
            'field_ids' => false,
            'zip_name'  => 'gf-uploads'
        ) );

        // time for hooks
        add_filter( 'gform_entry_meta',          array( $this, 'register_entry_meta'      ), 10, 2 );
        add_filter( 'gform_entries_field_value', array( $this, 'modify_zip_display_value' ), 10, 3 );

        add_action( 'gform_entry_created',       array( $this, 'archive_files'            ), 10, 2 );
        add_filter( 'gform_notification',        array( $this, 'add_zip_as_attachment'    ), 10, 3 );
        add_filter( 'gform_replace_merge_tags',  array( $this, 'all_files_merge_tag'      ), 10, 7 );

    }

    public function archive_files( $entry, $form ) {

        if( ! $this->is_applicable_form( $form ) || ! $this->has_applicable_field( $form ) )
            return;

        $archive_files = $this->get_entry_files( $entry, $form );
        if( empty( $archive_files ) )
            return;

        $archive_file_paths = wp_list_pluck( $archive_files, 'path' );

        $zip = $this->create_zip( $archive_file_paths, $this->get_zip_paths( $entry, 'path' ) );
        if( $zip )
            gform_update_meta( $entry['id'], $this->get_meta_key(), $this->get_zip_paths( $entry, 'url' ) );

    }

    /**
     * Get all files associated with an entry.
     *
     * @param $entry
     * @param $form
     *
     * @return array An array of files, each "file" including the 'path' and 'url' grouped by field ID:
     *
     *               array(
     *                  FIELD_ID => array(
     *                      'path' => '/path/to/file.ext',
     *                      'url'  => 'http://url.com/path/to/file.ext'
     *                  ),
     *                  FIELD_ID => array(
     *                      'path' => '/path/to/file.ext',
     *                      'url'  => 'http://url.com/path/to/file.ext'
     *                  )
     *               );
     *
     */
    public function get_entry_files( $entry, $form ) {

        $archive_files = array();

        foreach( $form['fields'] as $field ) {

            if( ! $this->is_applicable_field( $field ) )
                continue;

            $files = GFFormsModel::get_lead_field_value( $entry, $field );
            if( $this->is_multi_file( $field ) )
                $files = json_decode( $files );

            if( empty( $files ) )
                continue;

            if( ! is_array( $files ) )
                $files = array( $files );

            $index = 1;

            foreach( $files as $file ) {
                if( $file_path = $this->convert_url_to_path( $file ) ) {

                    $id = $field['id'];

                    if( $this->is_multi_file( $field ) ) {
                        $id = "{$id}.{$index}";
                        $index++;
                    }

                    $archive_files[$id] = array(
                        'path' => $file_path,
                        'url'  => $file
                    );

                }
            }

        }

        return $archive_files;
    }

    public function register_entry_meta( $entry_meta, $form_id ) {

        if( ! empty( $this->_args['field_ids'] ) )
            return $entry_meta;

        $entry_meta[$this->get_meta_key()] = array(
            'label'             => 'Form Uploads Zip File',
            'is_numeric'        => false,
            'is_default_column' => false
        );

        return $entry_meta;
    }

    public function modify_zip_display_value( $value, $form_id, $field_id ) {

        if( $field_id != $this->get_meta_key() )
            return $value;

        $value = sprintf( '<a href="%s">%s</a>', $value, __( 'Download Zip' ) );

        return $value;
    }

    public function is_applicable_form( $form ) {
        return ! $this->_args['form_id'] || $form['id'] == $this->_args['form_id'];
    }

    public function has_applicable_field( $form ) {

        foreach( $form['fields'] as $field ) {
            if( $this->is_applicable_field( $field ) )
                return true;
        }

        return false;
    }

    public function is_applicable_field( $field ) {

        $input_type = GFFormsModel::get_input_type( $field );

        $is_applicable_input_type = in_array( $input_type, array( 'fileupload', 'post_image' ) );
        $is_applicable_field_id   = empty( $this->_args['field_ids'] ) || in_array( $field['id'], $this->_args['field_ids'] );

        return $is_applicable_input_type && $is_applicable_field_id;
    }

    public function is_multi_file( $field ) {
        return rgar( $field, 'multipleFiles' );
    }

    public function convert_url_to_path( $url ) {

        $url = array_shift( explode( '|:|', $url ) );
        if( ! $url )
            return false;

        if( is_multisite() && get_site_option( 'ms_files_rewriting' ) ) {
            $path = preg_replace( '|^(.*?)/files/gravity_forms/|', BLOGUPLOADDIR . 'gravity_forms/', $url );
        } else {
            $path = str_replace( WP_CONTENT_URL, WP_CONTENT_DIR, $url );
        }

        return file_exists( $path ) ? $path : false;
    }

    public function create_zip( $files = array(), $destination = '', $overwrite = false ) {

        if( ! is_array( $files ) )
            return false;

        if( file_exists( $destination ) && ! $overwrite )
            return false;

        $valid_files = array();

        foreach( $files as $file ) {
            if( file_exists( $file ) )
                $valid_files[] = $file;
        }

        if( empty( $valid_files ) )
            return false;

        $zip = new ZipArchive();

        if( $zip->open( $destination, $overwrite ? ZIPARCHIVE::OVERWRITE : ZIPARCHIVE::CREATE ) !== true )
            return false;

        foreach( $valid_files as $file ) {
            $zip->addFile( $file, basename( $file ) );
        }

        $zip->close();

        return file_exists( $destination ) ? $destination : false;
    }

    public function get_zip_paths( $entry, $type = false ) {

        $filename = $this->get_zip_filename( $entry['id'] );
        $paths = GFFormsModel::get_file_upload_path( $entry['form_id'], $filename );

        foreach( $paths as &$path ) {
            $path = str_replace( basename( $path ), $filename, $path );
        }

        return $type ? rgar( $paths, $type ) : $paths;
    }

    public function get_zip_filename( $entry_id ) {
        return $this->get_slug( $this->_args['zip_name'], $entry_id, $this->_args['field_ids'] ) . '.zip';
    }

    public function get_meta_key( $entry_id = false ) {
        return $this->get_slug( 'gw_zip', $entry_id, $this->_args['field_ids'] );
    }

    public function get_slug( $name, $entry_id = false, $field_ids = array() ) {

        $bits = array( $name );

        if( $entry_id )
            $bits[] = $entry_id;

        if( ! empty( $field_ids ) )
            $bits[] = md5( implode( $field_ids ) );

        return implode( '_', $bits );
    }

    public function all_files_merge_tag( $text, $form, $entry ) {

        $search = '{all_files}';
        if( strpos( $text, $search ) === false )
            return $text;

        $replace = $this->get_all_files_output( $entry );

        return str_replace( $search, $replace, $text );
    }

    public function get_all_files_output( $entry ) {

        $zip_file = $this->get_zip_paths( $entry, 'path' );
        if( ! $zip_file )
            return '';

        $zip = new ZipArchive;
        if( ! $zip->open( $zip_file ) || $zip->numFiles <= 0 )
            return '';

        $files      = $this->get_entry_files( $entry, GFAPI::get_form( $entry['form_id'] ) );
        $file_urls  = wp_list_pluck( $files, 'url' );
        $file_links = array();

        foreach( $file_urls as $file_url ) {
            $file_links[] = sprintf( '<a href="%s">%s</a>', $file_url, basename( $file_url ) );
        }

        $replace = array_merge(
            array( __( 'Uploaded Files:' ) ),
            $file_links,
            array( sprintf( '<a href="%s">%s</a>', $this->get_zip_paths( $entry, 'url' ), __( 'All Files' ) ) )
        );

        $replace = implode( '<br />', $replace );

        return $replace;
    }

    public function add_zip_as_attachment( $notification, $form, $entry ) {

        if( $this->is_applicable_form( $form ) && $zip_path = $this->get_zip_paths( $entry, 'path' ) ) {

            if( isset( $notification['attachments'] ) ) {
                $notification['attachments'] = is_array( $notification['attachments'] ) ? $notification['attachments'] : array( $notification['attachments'] );
            } else {
                $notification['attachments'] = array();
            }

            $notification['attachments'][] = $zip_path;

        }

        return $notification;
    }

}

# Configuration

new GW_Zip_Files( array(
    'form_id' => 394,
    'zip_name' => 'my-sweet-archive'
) );