I am facing an error in extracting audio files uploaded in zip format. The error is as follows- Argument 2 passed to Drupal\Core\Archiver\Zip::extract() must be of the type array, string given,  

The following is the code:

public function buildForm(array $form, FormStateInterface $form_state, $node = NULL) {

// REMOVED PARTS OF CODE FOR READABILITY

if (isset($format) && $format == 'audio') {
$form['text_info']['fieldset']['source_formats']['audiofiles'] = [
'#type' => 'managed_file',
'#title' => $this->t('Upload zip file containing audios in mp3 format'),
'#upload_location' => 'public://file_uploads/audio/',
'#upload_validators' => $validators_zip,
];
}
}
$form['actions']['submit'] = [
'#type' => 'submit',
'#value' => $this->t('Import Content'),
];
return $form;
}

/**
* {@inheritdoc}
*/

/**
* Map content to the corresponding fields.
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$params['text'] = $form_state->getValue('text');
$index = 0;
$params['source_id'] = $form_state->getValue('sources');
$params['format'] = $form_state->getValue('format');

$uploaded_audio_file_id = $form_state->getValue('audiofiles')[0];
$format = $form_state->getValue('format');

// REMOVED CODE FOR READABILITY

if ($format == 'audio') {
$path = File::load($uploaded_audio_file_id)->getFileUri();

Zip::extract("public://file_uploads/audio/extract", $path); // IT IS THROWING ERROR ON THIS LINE
$uploaded_files = [];
// Dir to scan.
$d = dir("/");
// Mind the strict bool check!
while (FALSE !== ($entry = $d->read())) {
if ($entry[0] == '.') {
// Ignore anything starting with a dot.
continue;
}
$uploaded_files[] = $entry;
}
$d->close();
// Or whatever desired.
sort($uploaded_files);
//print_r($uploaded_files);exit;
}
$batch = [
'title' => $this->t('processing...'),
'operations' => $operations,
'finished' => '\Drupal\heritage_bulk_upload\ImportContent::importContentFinishedCallback',
];
batch_set($batch);
}

}
 

Comments

Jaypan’s picture

This:

$path = File::load($uploaded_audio_file_id)->getFileUri();

...is returning a string. extract() expects an array. Change to this:

$files = [File::load($uploaded_audio_file_id)->getFileUri()];
Zip::extract("public://file_uploads/audio/extract", $files);
Saptaparnee’s picture

Hi,

After making the changes, it now shows the error Error: Using $this when not in object context in Drupal\Core\Archiver\Zip::extract()

Please let me know what can I do about it?

Jaypan’s picture

That says to me you are calling Zip() directly, when it's a service. You'll need to find out which service to load, and use that.

Saptaparnee’s picture

I did not come across a service that deals with extracting the zip files...

Jaypan’s picture

There is a plugin manager for archivers: https://api.drupal.org/api/drupal/core%21core.services.yml/service/plugi...

You can likely use this plugin manager to retrieve the ZIP archiver, that will be loaded as a service.

Saptaparnee’s picture

Yes, I did come across that service but I did not find enough resources to  figure out how to extract the zip files. I am very new in Drupal and your help is greatly appreciated :)

I did something like, but it is throwing error:

$files = File::load($uploaded_audio_file_id)->getFileUri();
$zip = \Drupal::service('plugin.manager.archiver')->getInstance(['f‌​ilepath' => 'public://file_uploads/audio/extract']);
$zip->extract($files);
Jaypan’s picture

wombatbuddy’s picture

getInstance() expects the local path of your archive file, that is:

getInstance(['f‌​ilepath' => 'THE LOCAL PATH OF YOUR ARCHIVE FILE']);

And extract() expects the path where archive files will be extracted:

$zip->extract('THE DESTINATION PATH OF EXTRACTED FILES');

Here is the working example: 

<?php

namespace Drupal\my_module\Form;

use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Archiver\ArchiverManager;

/**
 * Class FileUploadForm.
 */
class FileUploadForm extends FormBase {

  /**
   * Drupal\Core\File\FileSystemInterface definition.
   *
   * @var \Drupal\Core\File\FileSystemInterface
   */
  protected $fileSystem;

  /**
   * Drupal\Core\Archiver\ArchiverManager definition.
   *
   * @var \Drupal\Core\Archiver\ArchiverManager
   */
  protected $pluginManagerArchiver;

  /**
   * Constructs a new FileUploadForm object.
   */
  public function __construct(FileSystemInterface $file_system, ArchiverManager $plugin_manager_archiver) {
    $this->fileSystem = $file_system;
    $this->pluginManagerArchiver = $plugin_manager_archiver;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('file_system'),
      $container->get('plugin.manager.archiver')
    );
  }

  /**
   * {@inheritdoc}
   */
  public function getFormId() {
    return 'file_upload_form';
  }

  /**
   * {@inheritdoc}
   */
  public function buildForm(array $form, FormStateInterface $form_state) {
    $form['file'] = [
      '#type' => 'file',
      '#title' => $this->t('Upload file'),
    ];

    $form['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Submit'),
    ];

    return $form;
  }

  /**
   * {@inheritdoc}
   */
  public function validateForm(array &$form, FormStateInterface $form_state) {
    $validators = [
      'file_validate_extensions' => ['zip'],
    ];

    if ($file = file_save_upload('file', $validators, 'public://')) {
      $form_state->setValue('file', $file);
    }
    else {
      $form_state->setErrorByName('file', $this->t('The file could not be uploaded.'));
    }
  }

  /**
   * {@inheritdoc}
   */
  public function submitForm(array &$form, FormStateInterface $form_state) {
    $file = $form_state->getValue(['file', 0]);
    $file->setPermanent();
    $file->save();

    // Archivers can only work on local paths.
    $fileRealPath = $this->fileSystem->realpath($file->getFileUri());

    $zip = $this->pluginManagerArchiver->getInstance(['filepath' => $fileRealPath]);
    // A file will be extracted to the public folder.
    $zip->extract('public://');
  }

}
Saptaparnee’s picture

Thank you, will try this one out :)

Saptaparnee’s picture

Hi, 

it gives me the error,  Call to a member function getFileUri() on string.

How can I fix this?

Jaypan’s picture

This will only give the File ID:

$file = $form_state->getValue(['file', 0]);

You need to load the file directly after that.

$fid = $form_state->getValue(['file', 0]);
if (is_numeric($fid)) {
  // Note: you should change the following to use dependency injection
  $file = \Drupal::entityTypeManager->getStorage('file')->load($fid);
  if ($file) {
    // Do stuff with your file
  }
}
Saptaparnee’s picture

I used dependency injection. Now I am getting the error Class 'ZipArchive' not found in Drupal\Core\Archiver\Zip->__construct() 

I have pasted the code here, I can't figure out where is the mistake. I have removed parts of code for readability purpose:

public function __construct(EntityTypeManagerInterface $entityTypeManager,FileSystemInterface $file_system, ArchiverManager $plugin_manager_archiver) {

    $this->entityTypeManager = $entityTypeManager;
    $this->fileSystem = $file_system;
    $this->pluginManagerArchiver = $plugin_manager_archiver;

  }

  public static function create(ContainerInterface $container) {
   return new static(
      $container->get('entity_type.manager'),
      $container->get('file_system'),
      $container->get('plugin.manager.archiver')

    );
  }

  public function getFormId() {
    return 'heritage_bulk_upload_import_content_text';
  }

  public function buildForm(array $form, FormStateInterface $form_state, $node = NULL) {

    // Code removed for readability
     $validators_zip = [
        'file_validate_extensions' => ['zip '],
      ];
      // Code removed for readability
      elseif (isset($format) && $format == 'audio') {
        $form['text_info']['fieldset']['source_formats']['audiofiles'] = [
          '#type' => 'managed_file',
          '#title' => $this->t('Upload zip file containing audios in mp3 format'),
          '#upload_location' => 'public://file_uploads/audio/',
          '#upload_validators' => $validators_zip,
        ];
      }
    }
    $form['actions']['submit'] = [
      '#type' => 'submit',
      '#value' => $this->t('Import Content'),
    ];
    return $form;
  }

  public function submitForm(array &$form, FormStateInterface $form_state) {
    
    $uploaded_audio_file_id = $form_state->getValue(['audiofiles',0]);
    $format = $form_state->getValue('format');
    
    // AUDIO FILES 
    
    elseif ($format == 'audio') {
     if (is_numeric($uploaded_audio_file_id)) {
        $file = $this->entityTypeManager->getStorage('file')->load($uploaded_audio_file_id);
      }
      if($file){

       $fileRealPath = $this->fileSystem->realpath($file->getFileUri());
       $zip = $this->pluginManagerArchiver->getInstance(['filepath' => $fileRealPath]);
      // A file will be extracted to the public folder.
      $zip->extract('public://file_uploads/audio/extract');
wombatbuddy’s picture

@Jaypan,

This will only give the File ID:

If you are talk about my code, then the file is loaded in validateForm() function. 

wombatbuddy’s picture

Removed duplication.