We regularly import content from old web sites and systems. One recent client had thousands of documents that we needed to copy from the old site, so we wrote a scraping system to import the ones that fit a certain template into Drupal, and just copy the existing documents into sites/default/files.
Using the Filefield_sources module, you can associate an existing file with a filefield, using IMCE or other files uploaded through the file system. However, we hit a problem: if you try to browse to an existing file, Filefield returns an error when you try to refer to it:
It turns out that Drupal stores a reference to each file in its internal files table, and you cannot add filefield links to a file without it already existing there. Why doesn't Filefield_sources simply add a reference? Because the underlying Filefield might delete the file when its node gets deleted. It's a bit of a mess, discussed more fully here. On that page, there's a new file attach method that gives you a drop-down of files uploaded to a particular directory, but we've got thousands of legacy files scattered deep in a tree, and this approach didn't work for us.
So our solution was to simply load all the files in the system into the files table, where Filefield can recognize them. Seems to work great!
To do this, I created a simple Drush script, and put in a module in the site. For example purposes, this would be in a mycustom.drush.inc file inside sites/all/modules/mycustom:
<?php
/**
* Provide module specific drush commands
*/
function mycustom_drush_command() {
$items = array();
$items['findpath'] = array(
'description' => 'Search filesystem for files by path',
'arguments' => array(
'filepath' => 'Name of path to find.',
'commit' => 'Save results to files table'
),
);
return $items;
}
/**
* Drush command callback
*/
function drush_mycustom_findpath($filepath,$commit = false){
$ar = file_scan_directory($filepath, '.*');
foreach ($ar as $item){
$file = new stdClass();
$file->filename = $item->basename;
$file->filepath = $item->filename;
// look for file in {files}
$result = db_query("SELECT * FROM {files} WHERE filepath LIKE '%s'", $file->filepath);
if ($obj = db_fetch_object($result)){
drush_log('Found file: '. $file->filename);
} else {
drush_log('File not found: '. $file->filename);
$file->uid = 1;
$file->filemime = file_get_mimetype($file->filename);
$file->status = FILE_STATUS_PERMANENT;
$file->filesize = filesize($file->filepath);
if ($commit){
drush_log('Saving file to database: '.$file->filename);
drupal_write_record('files',$file);
}
}
}
}
With that in place, Drush now recognizes a "drush findpath" command. This isn't very robust, but it does the trick...
To get a list of files and whether or not they are in the files table, you would change to the site root directory and run:
drush findpath --verbose sites/default/files
... this action does not actually do anything other than list each file it finds, along with whether it was found in the files database or not. To actually commit the files to the database, run:
drush findpath --verbose sites/default/files true
... and a minute or two later, you've got all the files added to the database!
Have you found a better way? Please let me know in the comments below...
Hehe.. that's the perfect solution I was looking for. Actually, my latest client's website need to import his documents too but didn't have solution. I got same error stating
"The selected file could not be used because the file does not exist in the database."
And now I got solution. I will post another comment or expect a mail from me if I strike with another error.
Regards
Facebook Application Analytics