2

Here is what I am trying to tackle: I would like to allow a zip file to be uploaded via the default filefield upload widget for a content type. I am using hook_node_presave to take the zip file and extract is using a helper function based off of the core update manager. The error I am receiving is:

Notice: Undefined index: filename in filefield_unzip_node_presave() (line 18 of /sites/all/modules/filefield_unzip/filefield_unzip.module). Notice: Undefined index: uri in filefield_unzip_node_presave() (line 19 of /sites/all/modules/filefield_unzip/filefield_unzip.module). Exception: Archivers can only operate on local files: >not supported in archiver_get_archiver() (line 8149 of /include /common.inc).

Here is my code:

/**
* @file

* Allows uploading and extracting a zip file uploaded to a file field.
*/

/**
 * 
 * Implementation of hook_node_presave($node)
 * 
 */

function filefield_unzip_node_presave($node) {
if($node->type == 'game') {
    if (!empty($node->field_game_files)) {
        $zipFile = $node->field_game_files['und'][0]['filename'];
        $zipDirectory = $node->field_game_files['und'][0]['uri'];

        _filefield_unzip_archive_extract($zipFile, $zipDirectory);
    }
}
}

/**
 * 
 * Copy of the function used by the update manager update_manager_archive_extract($file, $directory)
 * 
 */

function _filefield_unzip_archive_extract($file, $directory) {
$archiver = archiver_get_archiver($file);
if (!$archiver) {
    throw new Exception(t('Cannot extract %file, not a valid archive.', array('%file' => $file)));
}

//Remove the directory if it exists, otherwise it might contain a mixture of old files mixed with new files (e.g. in cases where files
//were removed from a later release).
$files = $archiver->listContents();

//Unfortunately, we can only use the direct name to determine the project name. Some archivers list the first file as the directory (i.e., MODULE/)
//and others list an actual file (i.e., MODULE/README.TXT).
$project = strtok($files[0], '/\\');

$extract_location = $directory . '/' .$project;
if (file_exists($extract_location)) {
    file_unmanaged_delete_recursive($extract_location);
}

$archiver->extract($directory);
return $archiver;
}
1
  • 1
    I found a solution to this, however stackexchange won't let me add an answer for 8 hours. I have it all typed out so if I forget to come back and upload it feel free to post on here to request the answer and remind me. Commented Feb 12, 2014 at 21:49

3 Answers 3

1

I found a solution to this, however stackexchange won't let me add an answer for 8 hours. I have it all typed out so if I forget to come back and upload it feel free to post on here to request the answer and remind me.

go on...

1
  • Sorry, DrupalDrop, just seeing this now. I have the answer typed out at the office and I am actually working from home today. Rather than attempt to recall all the details I will post the answer I have pre-written on Monday. Commented Feb 28, 2014 at 15:42
1

Okay, so after some additional digging I finally found the solution.

1) For the first two errors relating to undefined indexes...

It turns out that the entire file object is not loaded yet in hook_node_presave. This is why filename and uri are not defined. The only thing you can be sure has been set on the object at this point is the file's fid which is located in the file_managed table in the database and references the specific fields table which contains the rest of the metadata. A good explanation for how to grab the file by its fid and load the entire thing along with its metadata into your script can be found here: Changing the file of a file field (drupal 7)

2) The second problem was just a misread on my part. When using the archiver_get_archiver function you need to supply the full path to the file, not just the filename in the $file paramater (I was under the impression that the path was included in the $directory parameter), and then for the $directory parameter you substitute the location you actually want the file to be unzipped to.

Please see below for the updated code:

<?php

/**
 * @file

 * Allows uploading and extracting a zip file uploaded to a file field.
 */

/**
 * 
 * Implementation of hook_node_presave($node)
 * 
 */

function filefield_unzip_node_presave($node) {
    if($node->type == 'game') {
    //get fid from file_managed table in the DB
    $fid = $node->field_game_files[$node->language][0]['fid'];
    //load the file associated with this fid
    $file = file_load($fid);

    //get the full path to the file
    $zipFile = $file->uri;
    //remove the filename from the directory
    $zipDirectory = dirname($file->uri);

    if (!empty($node->field_game_files)) {
        _filefield_unzip_archive_extract($zipFile, $zipDirectory);
    }
}
}

/**
 * 
 * Copy of the function used by the update manager update_manager_archive_extract($file, $directory)
 * 
 */

function _filefield_unzip_archive_extract($file, $directory) {
$archiver = archiver_get_archiver($file);
if (!$archiver) {
    throw new Exception(t('Cannot extract %file, not a valid archive.', array('%file' => $file)));
}

//Remove the directory if it exists, otherwise it might contain a mixture of old files mixed with new files (e.g. in cases where files
//were removed from a later release).
$files = $archiver->listContents();

//Unfortunately, we can only use the direct name to determine the project name. Some archivers list the first file as the directory (i.e., MODULE/)
//and others list an actual file (i.e., MODULE/README.TXT).
$project = strtok($files[0], '/\\');

$extract_location = $directory . '/' .$project;
if (file_exists($extract_location)) {
    file_unmanaged_delete_recursive($extract_location);
}

$archiver->extract($directory);
return $archiver;
}
1

Couldn't review your complete code, but you can alter and use below code to get file path,

$imgpath = file_load($ifid)->uri; print file_create_url($imgpath);

hope it helps

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.