How can I process a file upload in a module configuration section? Here is what I have so far.
<?php
function dc_staff_directory_admin_settings()
{
$form['dc_staff_directory_upload_file'] = array(
'#type' => 'file',
'#title' => t('Upload staff directory excel (.xls) file'),
'#description' => t('Uploading a file will replace the current staff directory'),
);
$form['#submit'][] = 'dc_staff_directory_process_uploaded_file';
return system_settings_form($form);
}
function dc_staff_directory_process_uploaded_file($form, &$form_state)
{
//What can I do here to get the file data?
}
If you use the managed_file type instead Drupal will do most of the processing for you, you just need to mark the file for permanent storage in your submit function:
function dc_staff_directory_admin_settings() {
$form['dc_staff_directory_upload_file'] = array(
'#type' => 'managed_file',
'#title' => t('Upload staff directory excel (.xls) file'),
'#description' => t('Uploading a file will replace the current staff directory'),
'#upload_location' => 'public://path/'
);
$form['#submit'][] = 'dc_staff_directory_process_uploaded_file';
$form['#validate'][] = 'dc_staff_directory_validate_uploaded_file';
return system_settings_form($form);
}
function db_staff_directory_validate_uploaded_file($form, &$form_state) {
if (!isset($form_state['values']['dc_staff_directory_upload_file']) || !is_numeric($form_state['values']['dc_staff_directory_upload_file'])) {
form_set_error('dc_staff_directory_upload_file', t('Please select an file to upload.'));
}
}
function dc_staff_directory_process_uploaded_file($form, &$form_state) {
if ($form_state['values']['dc_staff_directory_upload_file'] != 0) {
// The new file's status is set to 0 or temporary and in order to ensure
// that the file is not removed after 6 hours we need to change it's status
// to 1.
$file = file_load($form_state['values']['dc_staff_directory_upload_file']);
$file->status = FILE_STATUS_PERMANENT;
file_save($file);
}
}
The validate function is probably a good idea as well, obviously you won't need it if the file is not a required field.
This is mostly taken from the image_example module, part of the Examples Module. If you really don't want to use the managed_file type have a look at the file_example module in that same collection, it has examples of how to uploaded an unmanaged file.
Hope that helps
Related
I have a custom form, with a field for the user to upload an image file (their logo). In the form validate hook, I've implemented file_save_upload, which is continually returning false. I can see that the file is in fact being saved in the correct location on upload, so why isn't file_save_upload working?
The form field:
$form['company_logo'] = array(
'#type' => 'managed_file',
'#title' => t('Company Logo'),
'#description' => t('Allowed extensions: gif png jpg jpeg'),
'#upload_location' => 'public://uploads/',
'#upload_validators' => array(
'file_validate_extensions' => array('gif png jpg jpeg'),
// Pass the maximum file size in bytes
//'file_validate_size' => array(MAX_FILE_SIZE*1024*1024),
),
);
The validation hook:
$file = file_save_upload( 'company_logo' , array(), 'public://uploads/', FILE_EXISTS_RENAME);
if (!$file) {
form_set_error('company_logo', t('Unable to access file or file is missing.'));
}
The managed file element handles moving the uploaded file for you, so there's no need to call file_save_upload() manually.
You're getting a NULL return because of these lines in file_save_upload():
// Make sure there's an upload to process.
if (empty($_FILES['files']['name'][$source])) {
return NULL;
}
As the file's already been processed there's nothing for the function to do.
You can persist the file entry by adding a submit handler to the form and using code similar to
$file = file_load($form_state['values']['company_logo']);
$file->status = FILE_STATUS_PERMANENT;
file_save($file);
Using the following code:
foreach ($form_state['values']['uploads'] as $key => $value) {
if (strlen($value)) {
$file = file_save_upload($key, array(
'file_validate_is_image' => array(), // Validates file is really an image.
'file_validate_extensions' => array('png gif jpg jpeg'), // Validate extensions.
));
// If the file passed validation:
if ($file) {
// Move the file, into the Drupal file system
if ($file = file_move($file, 'public://')) {
// Save the file for use in the submit handler.
$form_state['values']['uploaded_photos'][] = $file;
$x++;
} else {
form_set_error($key, t('Failed to write the uploaded file the site\'s file folder.'));
}
}
}
}
I am trying to save images attached to a form into a cached object with CTools. All of that was working fine, until I tried uploading the same file again, and I got a white screen that said "Error - The website encountered an error." (ripped from watchdog):
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'public://ad-10.jpg'; for key 2: UPDATE {file_managed} SET uid=:db_update_placeholder_0, filename=:db_update_placeholder_1, uri=:db_update_placeholder_2, filemime=:db_update_placeholder_3, filesize=:db_update_placeholder_4, status=:db_update_placeholder_5, timestamp=:db_update_placeholder_6
WHERE (fid = :db_condition_placeholder_0) ; Array
(
[:db_update_placeholder_0] => 0
[:db_update_placeholder_1] => ad-10.jpg
[:db_update_placeholder_2] => public://ad-10.jpg
[:db_update_placeholder_3] => image/jpeg
[:db_update_placeholder_4] => 4912
[:db_update_placeholder_5] => 0
[:db_update_placeholder_6] => 1326221376
[:db_condition_placeholder_0] => 834
)
";s:9:"%function";s:21:"drupal_write_record()";
Since I am not setting the $replace argument, shouldn't it default to FILE_EXISTS_RENAME and therefor not throw this error? How can I resolve this?
Try this module. It fixes the issue of concurrent file object being written to db. https://drupal.org/project/upload_qc
I can't comment as to why that doesn't work (it looks like it certainly should) but I can offer a simpler solution.
Drupal actually has a form widget built-in to handle file uploads, the managed_file type. It handles all of the file uploading/validating for you, you just need to mark the files as permanent in your form's submit handler.
So in your form function:
$form['files'] = array('#tree' => TRUE);
for ($i = 0; $i < $num_file_fields; $i++) {
$form['files']["file_$i"] = array(
'#type' => 'managed_file',
'#title' => 'Select a file',
'#upload_location' => 'public://',
'#upload_validators' => array(
'file_validate_is_image' => array(),
'file_validate_extensions' => array('png gif jpg jpeg')
)
);
}
And then in your submit handler:
$count = count($form_state['values']['files']);
for ($i = 0; $i < $count; $i++) {
$file = file_load($form_state['values']['files']["file_$i"]);
$file->status = FILE_STATUS_PERMANENT;
file_save($file);
}
Hope that helps
I had the same issue because of strange unused temporary files.
You can check if you have unused files using:
$result = db_select('file_managed', 'f')
->fields('f', array('fid'))
->condition('f.uri', db_like('temporary://') . '%', 'LIKE')
->execute()->fetchCol();
foreach ($result as $fid) {
if ($file = file_load($fid)) {
if (!file_usage_list($file)) {
dpm($file->filename);
}
}
}
If you fail to upload file with the same name that you see, you can remove them(But double check and backup first):
/**
* Clean unused temporary files.
*/
function MYMODULE_update_7007() {
$files = db_select('file_managed', 'f')
->fields('f', array('fid'))
->condition('f.uri', db_like('temporary://') . '%', 'LIKE')
->execute()->fetchCol();
foreach ($files as $fid) {
if ($file = file_load($fid)) {
$references = file_usage_list($file);
if (empty($references)) {
if (!file_delete($file)) {
watchdog('file system', 'Could not delete temporary file "%path" during garbage collection', array('%path' => $file->uri), WATCHDOG_ERROR);
}
}
else {
watchdog('file system', 'Did not delete temporary file "%path" during garbage collection, because it is in use by the following modules: %modules.', array('%path' => $file->uri, '%modules' => implode(', ', array_keys($references))), WATCHDOG_INFO);
}
}
}
}
I am sorry if this is a dumb question I have the following code
function trc_upload_file() {
$form['trc_upload_form'] = array(
'#type' => 'managed_file',
'#title' => 'Upload File',
'#descripion' => 'Uplaod files',
);
$form['#submit'][] = 'trc_upload_file_submit';
return $form;
}
function trc_upload_file_submit($form, &$form_state) {
$file = file_load($form_state['values']['trc_upload_form']);
$file->status = FILE_STATUS_PERMANENT;
file_save($file);
/*file_usage_add($file, 'trc_upload_page', 'user', $account->uid);*/
drupal_set_message(t('You Uploaded Successfully!'));
}
this is working fine
how to use file_usage_add() function, can i use it for user_roles instead individual users.
As Clive has confirmed, this should work:
file_usage_add($file, 'trc_upload_page', 'role', $roleID);
Let us know how you get on,
I have a file upload form
how can I retain this file when there are other validation errors so that the user doesn't have to upload the file again?
I tried this in my validation function but it doesn't work:
function mymodule_someform_validate($form, &$form_state) {
$form_state["values"]["some_field"] = some_value;
}
the $form_state["values"] variable is not available in my form definition function - mymodule_someform($form, &$form_state)
Any ideas?
Just use the managed_file type, it'll do it for you:
$form['my_file_field'] = array(
'#type' => 'managed_file',
'#title' => 'File',
'#upload_location' => 'public://my-folder/'
);
And then in your submit handler:
// Load the file via file.fid.
$file = file_load($form_state['values']['my_file_field']);
// Change status to permanent.
$file->status = FILE_STATUS_PERMANENT;
// Save.
file_save($file);
If the validation fails and the user leaves the form, the file will be automatically deleted a few hours later (as all files in the file_managed table without FILE_STATUS_PERMANENT are). If the validation doesn't fail, the submit handler will be run and the file will be marked as permanent in the system.
Admin form example for others who may be looking:
function example_admin_form(){
$form = array();
$form['image'] = array(
'#type' => 'managed_file',
'#name' => 'image',
'#title' => t('upload your image here!'),
'#default_value' => variable_get('image', ''),
'#description' => t("Here you can upload an image"),
'#progress_indicator' => 'bar',
'#upload_location' => 'public://my_images/'
);
// Add your submit function to the #submit array
$form['#submit'][] = 'example_admin_form_submit';
return system_settings_form($form);
}
function example_admin_form_submit($form, &$form_state){
// Load the file
$file = file_load($form_state['values']['image']);
// Change status to permanent.
$file->status = FILE_STATUS_PERMANENT;
// Save.
file_save($file);
}
Modifying download_count module to include information about users who downloaded files. Want to show this info on users' profile pages.
Here's the code:
function download_count_user($op, &$edit, &$account, $caterory = NULL) {
if ($op == 'view')
{
$result = db_query("SELECT filename FROM file_downloads_users WHERE user_id = %d", $account->uid);
while ($file_array = db_fetch_object($result)) {
$file_str .= $file->filename . '<br/>';
}
$items['downloads'] = array(
'title' => t('Files'),
'value' => $file_str,
'class' => 'member'
);
return array(t('Downloads')=>$items);
}
}
Doesn't give me any errors but doesn't show anything on My Account page either.
You don't want to modify a module. Drupal is built very very carefully to avoid having to hack core or contrib. Unless of course you are contributing a patch back.
The right way is to build your own custom module to do this (that would require the user downloads module) and implement the hook almost exactly what you're doing here.
The function is getting run (module enabled, var_dump ing or krumo'ing causes output?, cache cleared)
The way you are keying your variables is for Drupal 5.x and below. In D6, you add to $account->content. Which version of drupal are you using?
Check out user_user() (in user.module):
$account->content['user_picture'] = array(
'#value' => theme('user_picture', $account),
'#weight' => -10,
);
$account->content['summary']['file_downloads'] = array(
'#type' => 'user_profile_item',
'#title' => t('File Downloads'),
'#value' => $file_str,
'#weight' => 1
);