You are here

imce_unzip.module in IMCE unzip 7

Same filename and directory in other branches
  1. 6 imce_unzip.module

Main functions for IMCE unzip module

File

imce_unzip.module
View source
<?php

/**
 * @file
 * Main functions for IMCE unzip module
 */

/**
 * Implements hook_form_formID_alter().
 */
function imce_unzip_form_imce_profile_form_alter(&$form, &$form_state) {
  foreach (element_children($form['profile']['directories']) as $key) {
    $form['profile']['directories'][$key]['unzip'] = array(
      '#type' => 'checkbox',
      '#title' => t('Unzip files'),
      '#default_value' => isset($form_state['profile']['directories'][$key]['unzip']) ? $form_state['profile']['directories'][$key]['unzip'] : 0,
    );
    $form['profile']['maxfilestoextract'] = array(
      '#type' => 'textfield',
      '#title' => t('Maximum number of files to extract from a zip file'),
      '#description' => t('Define here the maximum number of files to extract from a zip file. For unlimited number of files, set this to 0. However this can increase server load.'),
      '#default_value' => isset($form_state['profile']['maxfilestoextract']) ? $form_state['profile']['maxfilestoextract'] : 50,
    );
  }
}

/**
 * Implements hook_form_formID_alter().
 */
function imce_unzip_form_imce_fileop_form_alter(&$form, &$form_state) {
  $imce =& $form_state['build_info']['args'][0]['imce'];
  if (imce_perm_exists($imce, 'unzip')) {
    $form['fset_unzip'] = array(
      '#type' => 'fieldset',
      '#title' => t('Unzip'),
    ) + imce_unzip_form($imce);
    $path = drupal_get_path('module', 'imce_unzip');
    drupal_add_js($path . '/imce_unzip.js');

    // drupal_add_css($path .'/imce_crop.css');
  }
}

/**
 * Unzip form.
 */
function imce_unzip_form(&$imce) {
  $form['deletezipfile'] = array(
    '#type' => 'checkbox',
    '#default_value' => 1,
    '#title' => t('Delete the zip file after unzip ?'),
  );
  $max_files_nb = '';
  if ($imce['maxfilestoextract']) {
    if ($imce['maxfilestoextract'] != 0) {
      $max_files_nb = '<div><em>' . t('Only %nb files will be extracted from the zip file', array(
        '%nb' => $imce['maxfilestoextract'],
      )) . '</em></div>';
    }
  }
  elseif ($imce['maxfilestoextract'] == 0) {
    $max_files_nb = '<div><em>' . t('Unlimited files will be extracted.', array(
      '%nb' => $imce['maxfilestoextract'],
    )) . '</em></div>';
  }
  else {
    $max_files_nb = '<div><em>' . t('Only 50 files will be extracted from the zip file') . '</em></div>';
  }
  $max_size_image = '';
  if ($imce['dimensions']) {
    $max_size_image = '<div><em>' . t('Extracted image files exceeding the maximum allowed image size (%dimensions) will be scaled down.', array(
      '%dimensions' => $imce['dimensions'],
    )) . '</em></div>';
  }
  $form['unzip'] = array(
    '#type' => 'submit',
    '#value' => t('Unzip'),
    // Permission for submission.
    '#submit' => $imce['perm']['unzip'] ? array(
      'imce_unzip_submit',
    ) : NULL,
    '#prefix' => '<div class="container-inline">' . t('Unzip the file ?'),
    '#suffix' => '</div>' . $max_files_nb . $max_size_image,
  );
  return $form;
}

/**
 * Submit unzip form.
 */
function imce_unzip_submit($form, &$form_state) {
  $form_state['redirect'] = FALSE;
  $imce =& $form_state['build_info']['args'][0]['imce'];
  $delete_zip_file = $form_state['values']['deletezipfile'];
  $unzip = imce_process_files($form_state['values']['filenames'], $imce, 'imce_unzip_file', array(
    $delete_zip_file,
  ));
  if (!empty($unzip)) {
    drupal_set_message(t('Unzip of %file successful', array(
      '%file' => $unzip[0],
    )));
  }
}

/**
 * unzip a file in the file list.
 */
function imce_unzip_file($filename, &$imce, $delete_zip_file) {
  $filepath = drupal_realpath(imce_dir_uri($imce)) . '/' . $filename;
  if (file_exists($filepath)) {
    $file = new stdClass();
    $file->filename = $filename;
    $file->uri = $filepath;
    $file->filemime = file_get_mimetype($filename);
    return _imce_unzip_file_unzip($file, $imce, $delete_zip_file);
  }
  return TRUE;
}

/**
 * Unzip the files and check extensions.
 */
function _imce_unzip_file_unzip($file, $imce, $delete_zip_file) {
  if ($file->filemime != 'application/zip') {
    drupal_set_message(t("No zip file"), NULL, array(
      'context' => 'error',
    ));
    return;
  }
  $zip = zip_open(realpath($file->uri));
  if (!is_resource($zip)) {
    drupal_set_message(t('Error for %uri = %error', array(
      '%uri' => $file->uri,
      '%error' => imce_unzip_err($zip),
    )), array(
      'context' => 'error',
    ));
    return;
  }
  if ($zip) {
    $nb = 0;
    $dirpath = drupal_realpath(imce_dir_uri($imce));
    $allowed_extensions = "";
    if ($imce['extensions'] != '*') {
      $allowed_extensions = explode(" ", $imce['extensions']);
    }
    else {
      $allowed_extensions = $imce['extensions'];
    }
    while ($zip_entry = zip_read($zip)) {
      if ($nb < $imce['maxfilestoextract'] || $imce['maxfilestoextract'] == 0) {
        $filename = zip_entry_name($zip_entry);

        // zipped filename of file
        $zdir = dirname(zip_entry_name($zip_entry));

        // zipped directory of file
        $ext = drupal_strtolower(array_pop(explode('.', $filename)));

        // zipped extension of file
        // Validate paths; ignore / do not extract Mac system files.
        if (drupal_strtolower($filename) != $ext && !preg_match('/^\\._/', $filename) && !preg_match('/\\.DS_Store$/', $filename) && !preg_match('/^__MACOSX/', $filename)) {

          // if $filename does not begin with '__MACOSX'
          // Create directory paths.
          $newdirpath = $dirpath . '/' . $zdir;
          if (!file_exists($newdirpath)) {
            if (module_exists('imce_mkdir') && $imce['perm']['mkdir'] && (!$imce['mkdirnum'] || $imce['mkdirnum'] > count($imce['subdirectories']))) {
              drupal_load('module', 'imce_mkdir');
              module_load_include('inc', 'imce_mkdir', 'imce_mkdir');
              $tmp = '';
              $tmp1 = '';
              $imcedir = $imce['dir'];
              foreach (explode('/', $zdir) as $k) {
                $tmp .= $k . '/';
                if (!file_exists($dirpath . '/' . $tmp)) {
                  $imce['dir'] .= $tmp1;
                  imce_mkdir_batch($imce, array(
                    $k,
                  ));
                }
                $tmp1 .= '/' . $k;
              }
              $imce['dir'] = $imcedir;
            }
            else {
              $filename = basename(zip_entry_name($zip_entry));
            }
          }

          // Create file paths.
          $afile = new stdClass();
          $afile->uri = $dirpath . '/' . $filename;
          $afile->filename = basename($afile->uri);
          $afile->filesize = zip_entry_filesize($zip_entry);
          $replace = variable_get('imce_settings_replace', FILE_EXISTS_RENAME);
          $afile->destination = file_destination(file_prepare_directory(dirname($afile->uri), FILE_MODIFY_PERMISSIONS | FILE_CREATE_DIRECTORY) ? $afile->uri : file_directory_temp() . '/_imce_unzip/' . $filename, $replace);

          // TODO: return error if file_prepare_directory() returns FALSE, rather than specifying sub-directory of temp directory as destination
          $validators = imce_validate_all($afile, $imce);
          if (!empty($validators)) {
            drupal_set_message(check_plain($validators), 'error');
          }
          else {

            // Validation ok.
            $new_file = new stdClass();
            $new_file->uri = $afile->destination;
            $new_file->filename = basename($new_file->uri);
            $new_file->filemime = file_get_mimetype($new_file->filename);
            $new_file->uid = $imce['uid'];
            $new_file->timestamp = time();
            $new_file->status = FILE_STATUS_PERMANENT;
            $new_file->filesize = zip_entry_filesize($zip_entry);
            $width = 0;
            $height = 0;

            // Check for image.
            if (zip_entry_open($zip, $zip_entry, "r")) {
              $buf = zip_entry_read($zip_entry, zip_entry_filesize($zip_entry));
              $image = imagecreatefromstring($buf);
              if ($image) {
                $width = imagesx($image);
                $height = imagesy($image);
              }
              zip_entry_close($zip_entry);
            }

            // Process image.
            if ($width && $height && $imce['dimensions'] != 0) {
              list($maxw, $maxh) = explode('x', $imce['dimensions']);
              if ($width > $maxw || $height > $maxh) {
                $scaled_file = _imce_unzip_scale_image($imce, $new_file, $maxw, $maxh, $buf, $zdir);
                if ($scaled_file) {
                  drupal_set_message(t('Extraction and scaling of %filename to fit maximum dimensions of ' . $maxw . 'x' . $maxh . ' pixels.', array(
                    '%filename' => $scaled_file->filename,
                  ), array(
                    'context' => 'success',
                  )));
                }
              }
              else {
                $fp = fopen($new_file->uri, "w+");
                fwrite($fp, $buf);
                fclose($fp);
                $new_file->width = $width;
                $new_file->height = $height;
                $new_file->uri = imce_dir_uri($imce) . ($zdir != '.' ? $zdir . '/' : '') . $new_file->filename;

                // stream wrapper URI relative to IMCE working directory
                // If entry for file already exists in database, register update
                $update = array();
                if ($_file = db_query("SELECT f.* FROM {file_managed} f WHERE f.uri = :path", array(
                  ':path' => $new_file->uri,
                ))
                  ->fetchObject()) {
                  $new_file->fid = $_file->fid;
                  $update[] = 'fid';
                }

                // Register file in database
                drupal_write_record('file_managed', $new_file, $update);
                $new_file->fid = db_query("SELECT fid FROM {file_managed} f WHERE f.uri = :path", array(
                  ':path' => $new_file->uri,
                ))
                  ->fetchField();
                imce_add_file($new_file, $imce);
                imce_file_register($new_file);
                drupal_set_message(t('Extraction of %filename.', array(
                  '%filename' => $new_file->filename,
                ), array(
                  'context' => 'success',
                )));
              }
            }
            else {
              $fp = fopen($new_file->uri, "w+");
              if ($fp) {
                fwrite($fp, $buf);
                fclose($fp);
                $new_file->width = 0;
                $new_file->height = 0;
                $new_file->uri = imce_dir_uri($imce) . ($zdir != '.' ? $zdir . '/' : '') . $new_file->filename;

                // stream wrapper URI relative to IMCE working directory
                // If entry for file already exists in database, register update
                $update = array();
                if ($_file = db_query("SELECT f.* FROM {file_managed} f WHERE f.uri = :path", array(
                  ':path' => $new_file->uri,
                ))
                  ->fetchObject()) {
                  $new_file->fid = $_file->fid;
                  $update[] = 'fid';
                }

                // Register file in database
                drupal_write_record('file_managed', $new_file, $update);
                $new_file->fid = db_query("SELECT fid FROM {file_managed} f WHERE f.uri = :path", array(
                  ':path' => $new_file->uri,
                ))
                  ->fetchField();
                imce_add_file($new_file, $imce);
                imce_file_register($new_file);
                drupal_set_message(t('Extraction of %filename', array(
                  '%filename' => $new_file->filename,
                ), array(
                  'context' => 'success',
                )));
              }
              else {
                drupal_set_message(t("Can't create %filename", array(
                  '%filename' => $new_file->filename,
                ), array(
                  'context' => 'error',
                )));
              }
            }
            $nb++;

            // End validator empty.
          }

          // End ext != filename.
        }

        // End nb extracted files.
      }

      // End while $zip_entry = zip_read($zip).
    }
    if ($imce['perm']['delete'] && $delete_zip_file) {
      $deleted = imce_process_files(array(
        $file->filename,
      ), $imce, 'imce_delete_file');
      if (!empty($deleted)) {
        drupal_set_message(t('File deletion successful: %files.', array(
          '%files' => utf8_encode(implode(', ', $deleted)),
        )));
      }
    }
    zip_close($zip);
  }
  else {
    drupal_set_message(check_plain(t('Error for ' . $file->uri)), array(
      'context' => 'error',
    ));
  }
  return;
}

/**
 * Nice error messages for zip.
 * See http://php.net/manual/en/function.zip-open.php.
 */
function imce_unzip_err($errno) {
  $zip_errors = array(
    'ZIPARCHIVE::ER_MULTIDISK' => t('Multi-disk zip archives not supported.'),
    'ZIPARCHIVE::ER_RENAME' => t('Renaming temporary file failed.'),
    'ZIPARCHIVE::ER_CLOSE' => t('Closing zip archive failed'),
    'ZIPARCHIVE::ER_SEEK' => t('Seek error'),
    'ZIPARCHIVE::ER_READ' => t('Read error'),
    'ZIPARCHIVE::ER_WRITE' => t('Write error'),
    'ZIPARCHIVE::ER_CRC' => t('CRC error'),
    'ZIPARCHIVE::ER_ZIPCLOSED' => t('Containing zip archive was closed'),
    'ZIPARCHIVE::ER_NOENT' => t('No such file.'),
    'ZIPARCHIVE::ER_EXISTS' => t('File already exists'),
    'ZIPARCHIVE::ER_OPEN' => t("Can't open file"),
    'ZIPARCHIVE::ER_TMPOPEN' => t('Failure to create temporary file.'),
    'ZIPARCHIVE::ER_ZLIB' => t('Zlib error'),
    'ZIPARCHIVE::ER_MEMORY' => t('Memory allocation failure'),
    'ZIPARCHIVE::ER_CHANGED' => t('Entry has been changed'),
    'ZIPARCHIVE::ER_COMPNOTSUPP' => t('Compression method not supported.'),
    'ZIPARCHIVE::ER_EOF' => t('Premature EOF'),
    'ZIPARCHIVE::ER_INVAL' => t('Invalid argument'),
    'ZIPARCHIVE::ER_NOZIP' => t('Not a zip archive'),
    'ZIPARCHIVE::ER_INTERNAL' => t('Internal error'),
    'ZIPARCHIVE::ER_INCONS' => t('Zip archive inconsistent'),
    'ZIPARCHIVE::ER_REMOVE' => t("Can't remove file"),
    'ZIPARCHIVE::ER_DELETED' => t('Entry has been deleted'),
  );
  $errmsg = 'unknown';
  foreach ($zip_errors as $const_name => $error_message) {
    if (defined($const_name) and constant($const_name) === $errno) {
      return t('Zip File Function error: %error', array(
        '%error' => $error_message,
      ));
    }
  }
  return t('Zip File Function error: unknown - %error', array(
    '%error' => $errno,
  ));
}

/**
 * Ajax operation: unzip
 */
function imce_js_unzip(&$imce) {
  if ($imce['perm']['unzip']) {
    $_POST['op'] = t('Unzip');
    return imce_process_fileop($imce);
  }
}

/**
 * Private function for scaling and saving images.
 */
function _imce_unzip_scale_image($imce, $file, $maxw, $maxh, $buf, $zdir) {

  // Write contents of buffer
  $temp_file_path = tempnam(realpath(file_directory_temp() . '/_imce_unzip'), 'imce');
  register_shutdown_function('file_unmanaged_delete', $temp_file_path);
  $fp = fopen($temp_file_path, "w+");
  fwrite($fp, $buf);
  fclose($fp);

  // Load and attempt to scale the image from buffer
  $image = image_load($temp_file_path);
  if (!$image || !image_scale($image, $maxw, $maxh)) {
    drupal_set_message(t('%filename cannot be resized.', array(
      '%filename' => utf8_encode($file->filename),
    ), array(
      'context' => 'error',
    )), 'error', FALSE);
    return FALSE;
  }

  // Copy scaled image to another temp file (this time with stream wrapper URI)
  if (!($tempuri = drupal_tempnam('temporary://_imce_unzip/', 'imce'))) {
    return FALSE;
  }
  register_shutdown_function('file_unmanaged_delete', $tempuri);
  if (!image_save($image, $tempuri) || !$image->info) {
    return FALSE;
  }
  $imguri = imce_dir_uri($imce) . ($zdir != '.' ? $zdir . '/' : '') . $file->filename;

  // stream wrapper URI relative to IMCE working directory
  // Create file object
  $new_file = new stdClass();
  $new_file->uri = $imguri;
  $new_file->filename = basename($new_file->uri);

  // Validate quota
  $new_file->filesize = $image->info['file_size'];
  $quotadiff = $new_file->filename == $file->filename ? -$file->filesize : 0;
  if (!imce_validate_quotas($new_file, $imce, $quotadiff)) {
    return FALSE;
  }

  // Build the rest of the file object
  $new_file->uid = $imce['uid'];
  $new_file->filemime = $image->info['mime_type'];
  $new_file->status = FILE_STATUS_PERMANENT;
  $new_file->timestamp = REQUEST_TIME;

  // Copy from temp to file uri
  $destination = $new_file->uri;
  $new_file->uri = $tempuri;
  if (!($new_file = file_copy($new_file, $destination, FILE_EXISTS_REPLACE))) {
    return FALSE;
  }
  imce_file_register($new_file);

  // Add to the list
  $new_file->width = $image->info['width'];
  $new_file->height = $image->info['height'];
  imce_add_file($new_file, $imce);

  // If entry for file already exists in database, register update
  $update = array();
  if ($_file = db_query("SELECT f.* FROM {file_managed} f WHERE f.uri = :path", array(
    ':path' => $new_file->uri,
  ))
    ->fetchObject()) {
    $new_file->fid = $_file->fid;
    $new_file->uid = $_file->uid;
    $update[] = 'fid';
  }

  // Register file in database
  drupal_write_record('file_managed', $new_file, $update);
  return $new_file;
}

Functions

Namesort descending Description
imce_js_unzip Ajax operation: unzip
imce_unzip_err Nice error messages for zip. See http://php.net/manual/en/function.zip-open.php.
imce_unzip_file unzip a file in the file list.
imce_unzip_form Unzip form.
imce_unzip_form_imce_fileop_form_alter Implements hook_form_formID_alter().
imce_unzip_form_imce_profile_form_alter Implements hook_form_formID_alter().
imce_unzip_submit Submit unzip form.
_imce_unzip_file_unzip Unzip the files and check extensions.
_imce_unzip_scale_image Private function for scaling and saving images.