欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

Drupal 6 file upload validate 进行验证上传文件 有大用

shiping1 的头像

//下面是自己亲自做的例子
//表单函数_validate 验证类似于钩子函数的回调函数
function zhuqutel_form_validate(&$form, &$form_state)
{
    /**
   * 用户提交的所有数据在 $form_state['values'] 之中,相当于 $_POST
   */
   $field = 'upload';
   $directory = file_directory_path().'/zhuaqutelqq';
   
    if (
file_check_directory($directory, FILE_CREATE_DIRECTORY, $field)) {
         $size_limit = file_upload_max_size();
         $validators = array(
        'file_validate_extensions' =>  array('xls'),
        'file_validate_size' => array(
            array($size_limit),
        ),
       );
       if ($file =
file_save_upload($field, $validators, $directory)) {
 
              // Set the file's status to permanent, which will prevent Drupal's file
              // garbage collection from deleting it.
              file_set_status($file, FILE_STATUS_PERMANENT);
              // We add our final file object to the form's storage array, so that it gets passed
              // through to the form's submit handler, where we can act on it.
              $form_state['storage']['upload'] = $file;
 
       }else{
             form_set_error('','上传发生错误');
       }
    }
   
    // form_set_error('',$form_values['name']);
 
}



Drupal: File upload required?

$form_id = "upload_form";


$form[$form_id] = array (
    '#type' => 'fieldset',
    '#description' => t('This is a utility to import nodes from a Comma Separated Value file. To begin, pick a node type, and upload a CSV.'),
);

$form[$form_id]['type'] = array(
    '#title' => t('Enter node type'),
    '#type' => 'textfield',
//      '#autocomplete_path' => '', TODO: autocomplete for node types
    '#required' => TRUE,
    '#description' => t('This node type should already exist. If it doesn\'t, create it first.'),
);

$form[$form_id]['upload'] = array(
    '#type' => 'file',
    '#title' => t('Upload CSV file'),
//      '#size' => 40,
    '#description' => t('This will not work for a non-CSV file.'),
//      '#required' => TRUE, TODO: breaks it. why?
);

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

$form['#attributes'] = array('enctype' => 'multipart/form-data');

 

正确答案  This is my workaround to make file field required:

<?    
    // A piece of form that defines the file field
    $form['attachment'] = array(
        '#type' => 'file',
        '#title' => t('Title'),
        //'#required' => TRUE,   // check this manually
    );

    // Form validation hook
    function yourformname_validate($form, &$form_state) {
        // Validate file
        $validators = array(
            'file_validate_extensions' => array('doc txt pdf'), // does not work for user 1
            'file_validate_size' => array(1000000, 0),
        );
        $file = file_save_upload('attachment', $validators, file_directory_path());
        if ($file) {
             $form_state['values']['attachment'] = $file; // drupal file object
        }
        else{
             form_set_error('attachment', "File is required");
        }
    }
?>

来自 http://stackoverflow.com/questions/1996134/drupal-file-upload-required


Drupal 6 File Handling


 

I am handling file upload field in a form using Drupal 6 form APIs. The file field is marked as required. I am doing all the right steps in order to save and rename files in proper locations.

upload form

$form = array();
....
$form['image'] = array(
    '#type' => 'file',
    '#title' => t('Upload photo'),
    '#size' => 30,
    '#required' => TRUE,
);
$form['#attributes'] = array('enctype' => "multipart/form-data");
...

form validate handler

$image_field = 'image';

if (isset($_FILES['files']) && is_uploaded_file($_FILES['files']['tmp_name'][$image_field])) {
    $file = file_save_upload($image_field);
    if (!$file) {
        form_set_error($image_field, t('Error uploading file'));
        return;
    }
    $files_dir = file_directory_path();
    $contest_dir = 'contest';

    if(!file_exists($files_dir . '/' . $contest_dir) || !is_dir($files_dir . '/' . $contest_dir))
        mkdir($files_dir . '/' . $contest_dir);


    //HOW TO PASS $file OBJECT TO SUBMIT HANDLER
    $form_state['values'][$image_field] = $file;
    file_move($form_state['values'][$image_field], $files_dir."/" . $contest_dir . "/contest-". $values['email']. "-" . $file->filename);
}
else {
    form_set_error($image_field, 'Error uploading file.');
    return;
}





 

正确答案  your handler is wrong. You never should touch $_FILES or $_POST variables in drupal, instead you should only use the drupal tools. Said that, the implementation you should is like that:

upload form

function my_form_handler(&$form,&$form_state){/** VALIDATION FILE * */
 $extensions = 'jpeg jpg gif tiff';
 $size_limit = file_upload_max_size(); 
 $validators = array(
      'my_file_validate_extensions' => array($extensions),
      'my_file_validate_size' => array($size_limit),
  );

 $dest = file_directory_path();
 if ($file = file_save_upload('image', $validators, $dest)) {
  //at this point your file is uploaded, moved in the files folder and saved in the DB table files
 }
}

    


来自 http://stackoverflow.com/questions/4354708/drupal-6-file-handling


In drupal 6, How to process uloaded file in more than one steps?

I am writing custom module in drupal.

Aim is to :

1. Upload a csv file
2. Display its content in a tabular layout.
3. On confirmation, save it in database.

Problem I am facing:

  1. I am unable to upload any file. I am not getting any thing in $_FILES, even if I upload or not. >> SOLVED

  2. How do I split the process ? Suppose I succeed in uploading file [with your help indeed ;) ], and I save the file, suppose in drupal6/uploaded_data directory. How do I redirect to next page where I can read from file and show tabular data for confirmation.

Codes :) 
menu hooks and all

function productsadmin_menu() {
    $items['admin/settings/product-administration'] = array(
        'title' => 'Product Administration',
        'description' => 'Upload products data',
        'page callback' => 'productsadmin_form',
        'access arguments' => array('access content'),
        'type' => MENU_NORMAL_ITEM,
    );
    return $items;
}

function productsadmin_form() {
    return drupal_get_form('productsadmin_my_form');
}

This function is passed to drupal_get_form()

function productsadmin_my_form() {
  $form['#attributes'] = array('enctype' => "multipart/form-data");

  $form['csv'] = array(
    '#type' => 'file',
    '#title' => 'Product Catalog',
    '#description' => 'Product catalog in specified csv format',
    '#required' => FALSE,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  return $form;
}

Validation (The part which is not working is commented)

function productsadmin_my_form_validate($form, &$form_state) {
    if($form_state['values']['csv'] == "") {
        form_set_error('csv', t('Please input product catalog csv data'));
    }

/*  // Check if file is uploaded (Not working)
    if ($_FILES['files']['name']['csv'] == '') {
        form_set_error('csv', t('Please upload product catalog' . $rahul_vals));
    }
*/
}

Submit action

function productsadmin_my_form_submit($form, &$form_state) {
    /*
        1. Move File to uploaded_dir
        2. Change the header so that it is redirected to new page
    */
}

正确答案

you shouldn't use $_FILES in drupal,use drupal api

I made this example for you to explain how to work with cvs

 

/**
    * Form function  
    */
     function _form_cvs_import($form_state) {
      $form['#attributes'] = array('enctype' => "multipart/form-data");
      $form['container'] = array(
        '#type' => 'fieldset', 
        '#title' => t('CVS UPLOAD') , 
      );
      $form['container']['cvs_file'] = array(
        '#type' => 'file' ,  
        '#title' => t('CVS FILE') , 
        '#description' => t('insert your cvs file here') , 
      ) ;   
      $form['container']['submit'] = array(
        '#type' => 'submit' ,  
        '#value' => t('SEND') , 
      ) ;       
 
       return $form ; 
    }
 
/**
* form validate
*/
function _form_cvs_import_validate($form, $form_state) {
 $validators = array(
  'file_validate_extensions' => array('cvs'),
 );
 if(!file_save_upload('cvs_file', $validators)) { // the file is not submitted
    form_set_error('cvs_file', 'Please select the cvs file') ;  
 }else{ // the file is submitted another validation for extension
   $file = file_save_upload('cvs_file', $validators, file_directory_path()) ; 
   if($file->filemime != 'application/octet-stream' ) {
     form_set_error('cvs_file', 'Extensions Allowed : cvs') ;       
   }        
 }      
}
 
 
/**
*  form submit
*/
function _form_cvs_import_submit($form, $form_state) {
    $file = file_save_upload('cvs_file', $validators, file_directory_path()) ;  // this is the cvs file in the tmp directory
    $file_handler = fopen($file->filepath, 'r') ; // open this cvs file
    $line_num = 0 ;
    $fields = array() ;  
    while(!feof($file_handler)) { 
        $line_num++ ; 
        $line = fgets($file_handler) ; // this is the line/row
        $line_array = explode(",", $line);  //  array of row fields
        $field_num = 0 ;  
        foreach($line_array as $field) { 
            $field_num++ ; 
            $fields[$line_num][$field_num] = str_replace('"', '', $field );  // E.g you can access second row and third field by $fields[2][3]
        }   
    }
    fclose($file_handler);
    unlink($file->filepath);

 

/**
    * Form function  
    

来自 http://stackoverflow.com/questions/7530377/in-drupal-6-how-to-process-uloaded-file-in-more-than-one-steps


How do I validate file type in Drupal 6 with file_save_upload?


I am working on a module that takes a user-uploaded CSV file. Code looks like this:

function foo_form_submit($form_id, &$form_state) {
  $validators = array();
  $dest = 'sites/phoenix.dev/files';
  $uploaded_file = file_save_upload('upload', $validators, $dest);
//some other stuff
}

As you can see, I don't pass anything in to validate that the file in the 'upload' field is actually a .csv file. This would cause some nasty things to happen later on in the function. How do I use the validators to check that the extension is .csv, or even better, to check that it actually IS a .csv file?

Edit: and Google search did not turn up anything too helpful.
 

正确答案

Drupal documentation on file_validate_extensions suggests you want to change this:

$validators = array();

To this:

$validators = array( 'file_validate_extensions' => array( 'csv' ) );

来自 http://stackoverflow.com/questions/769875/how-do-i-validate-file-type-in-drupal-6-with-file-save-upload


Add image file programmatically in drupal 6


i want to upload an image on my site. I have a custom form in a module with

  $form['picture'] = array(
  '#type'   => 'file',
  '#title'  => t('Avatar'),
  '#prefix' => '<img src="' . $user->picture . '">'
  );

  $form['#validate'][] = 'product_validate_picture';

and in my validate fucntion :

$validators = array('file_validate_extensions' => array('jpg png'),
                    'file_validate_image_resolution' => array('500x500'));

$file = file_save_upload('picture', $validators);
dsm($file);

The problem is that i do not get the picture returned by the form, i only get "0" which is an error. So, did i do something wrong, or another method is better to get and save a picture returned by a custom form?

Thanks.

正确答案

I found a sample for implement it in drupal 6

maybe your problem occur because of 2 thing,

  • permission of directory

  • $form['#attributes'] = array('enctype' => "multipart/form-data");

made this example for you...explain how to working with cvs
 

 /**
    * Form function  
    */
     function _form_cvs_import($form_state) {
      $form['#attributes'] = array('enctype' => "multipart/form-data");
      $form['container'] = array(
        '#type' => 'fieldset', 
        '#title' => t('CVS UPLOAD') , 
      );
      $form['container']['cvs_file'] = array(
        '#type' => 'file' ,  
        '#title' => t('CVS FILE') , 
        '#description' => t('insert your cvs file here') , 
      ) ;   
      $form['container']['submit'] = array(
        '#type' => 'submit' ,  
        '#value' => t('SEND') , 
      ) ;       

       return $form ; 
    }

/**
* form validate
*/
function _form_cvs_import_validate($form, $form_state) {
 $validators = array(
  'file_validate_extensions' => array('cvs'),
 );
 if(!file_save_upload('cvs_file', $validators)) { // the file is not submitted
    form_set_error('cvs_file', 'Please select the cvs file') ;  
 }else{ // the file is submitted another validation for extension
   $file = file_save_upload('cvs_file', $validators, file_directory_path()) ; 
   if($file->filemime != 'application/octet-stream' ) {
     form_set_error('cvs_file', 'Extensions Allowed : cvs') ;       
   }        
 }      
}


/**
*  form submit
*/
function _form_cvs_import_submit($form, $form_state) {
    $file = file_save_upload('cvs_file', $validators, file_directory_path()) ;  // this is the cvs file in the tmp directory
    $file_handler = fopen($file->filepath, 'r') ; // open this cvs file
    $line_num = 0 ;
    $fields = array() ;  
    while(!feof($file_handler)) { 
        $line_num++ ; 
        $line = fgets($file_handler) ; // this is the line/row
        $line_array = explode(",", $line);  //  array of row fields
        $field_num = 0 ;  
        foreach($line_array as $field) { 
            $field_num++ ; 
            $fields[$line_num][$field_num] = str_replace('"', '', $field );  // E.g you can access second row and third field by $fields[2][3]
        }   
    }
    fclose($file_handler);
    unlink($file->filepath);

来自  http://drupal.stackexchange.com/questions/99391/add-image-file-programmatically-in-drupal-6

 

Handling image uploads with custom validation using the Drupal 6 Forms API

 

I've recently had to go through the exercise again of building a bespoke form in Drupal 6 that accepts a file upload, validates it and saves it into to the server. Not doing this nearly enough to have it committed to memory means numerous trips to Google and frequent dives into the Drupal forms API are the order of the day. I've distilled my code into a working example that I hope will serve as future reference.

The sample code below assumes that you're comfortable creating a Drupal module, and have created a form using the forms API.

First we define a form with a single upload field and a submit button:

function module_image_form() {
  
  // Set the form's enctype to allow it to handle file uploads
  $form['#attributes']['enctype'] = "multipart/form-data";
    
  $form['logo'] = array(
    '#type' => 'file',
    '#title' => t('Logo'),
  );
  
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Save'),
  );
  
  return $form;
  
}

Next we define the form's validate function which, after ensuring that the uploaded image meets our validation requirements, will handle the actual upload. Drupal provides built-in validation to check for a valid image, but we won't learn very much from using that. Instead, we specify our own validation function to prevent GIFs from being uploaded. We'll use Drupal's own mechanism for validating the image dimensions though.

function module_image_form_validate($form, &$form_state) {
 
  // Set this to the name of the form's file field
  $field = 'logo';
 
  // The directory the image will be saved to (file_directory_path()
  // returns the path to your default files directory).
  $directory = file_directory_path() . '/images';
 
  // Drupal will attempt to resize the image if it is larger than
  // the following maximum dimensions (width x height)
  $max_dimensions = '800x600';
  
  // We don't care about the minimum dimensions
  $min_dimensions = 0;
 
  // file_check_directory() ensures the destination directory is valid and
  // will attempt to create it if it doesn't already exist.
  if (file_check_directory($directory, FILE_CREATE_DIRECTORY, $field)) {
 
    // Specify the validators. The first is Drupal's built-in function for validating
    // the image's dimensions. The second is our custom validator to exclude GIFs.
    $validators = array(
      'file_validate_image_resolution' => array($max_dimensions, $min_dimensions),
      'module_validate_image_type' => array(),
    );
 
    // Move the file to its final location if the validators pass, else
    // return to the form and display the errors.
    if ($file = file_save_upload($field, $validators, $directory)) {
 
      // Set the file's status to permanent, which will prevent Drupal's file
      // garbage collection from deleting it.
      file_set_status($file, FILE_STATUS_PERMANENT);
 
      // We add our final file object to the form's storage array, so that it gets passed
      // through to the form's submit handler, where we can act on it.
      $form_state['storage']['file'] = $file;
 
    }
  }
}

This is our custom validator, which simply checks to see that the uploaded image does not have a MIME type of image/gif:

function module_validate_image_type($file) {
  $errors = array();
  $info = image_get_info($file->filepath);
  if ($info['mime_type'] == 'image/gif') {
    $errors[] = t('Only JPEG and PNG images are allowed.');
  }
  return $errors;
}

Finally, we implement the form's submit handler. The successfully uploaded image will be passed to it in the $form_state variable. I'll leave the submit handler blank, because what happens next depends entirely on what you're trying to achieve.

function module_sample_form_submit($form, &$form_state) {
  // print_r($form_state['storage']['file']) to view the uploaded file's details
}


 

The form_example_tutorial.inc Drupal example source code



<?php

/**
 * @file
 * This is the Form API Tutorial from the handbook.
 * @see http://drupal.org/node/262422
 *
 * It goes through ten form examples in increasing complexity to demonstrate
 * Drupal 6 Form API.
 *
 * Links are provided inline for the related handbook pages.
 */

function form_example_tutorial() {
  return t('This is a set of ten form tutorials tied to the <a href="http://drupal.org/node/262422">Drupal handbook</a>.');
}

//////////////// Tutorial Example 1 //////////////////////
/**
 * This first form function is from the handbook page at
 * http://drupal.org/node/717722.
 * It just creates a very basic form with a textfield.
 *
 * This function is called the "form builder". It builds the form.
 * It takes a single argument, $form_state, but if drupal_get_form()
 * sends additional arguments, they will be provided after $form_state.
 */

function form_example_tutorial_1($form_state) {

  $form['description'] = array(
    '#type' => 'item',
    '#title' => t('A form with nothing but a textfield'),
  );
  // This is the first form element. It's a textfield with a label, "Name"
  $form['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Name'),
  );
  return $form;
}


//////////////// Tutorial Example 2 //////////////////////

/**
 * This is Example 2, a basic form with a submit button.
 * @see http://drupal.org/node/717726
 */
function form_example_tutorial_2(&$form_state) {
  $form['description'] = array(
    '#type' => 'item',
    '#title' => t('A simple form with a submit button'),
  );

  $form['name'] = array(
    '#type' => 'textfield',
    '#title' => t('Name'),
  );

  // Adds a simple submit button that refreshes the form and clears its contents -- this is the default behavior for forms.
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  return $form;
}

//////////////// Tutorial Example 3 //////////////////////

/**
 * Example 3: A basic form with fieldsets.
 *
 * We establish a fieldset element and then place two text fields within
 * it, one for a first name and one for a last name. This helps us group
 * related content.
 *
 * Study the code below and you'll notice that we renamed the array of the first
 * and last name fields by placing them under the $form['name']
 * array. This tells Form API these fields belong to the $form['name'] fieldset.
 */
function form_example_tutorial_3(&$form_state) {
  $form['description'] = array(
    '#type' => 'item',
    '#title' => t('A form with a fieldset'),
  );

  $form['name'] = array(
    '#type' => 'fieldset',
    '#title' => t('Name'),
  );
  $form['name']['first'] = array(
    '#type' => 'textfield',
    '#title' => t('First name'),
  );
  $form['name']['last'] = array(
    '#type' => 'textfield',
    '#title' => t('Last name'),
  );


  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  return $form;
}


//////////////// Tutorial Example 4 //////////////////////

/**
 * Example 4: Basic form with required fields.
 *
 */
function form_example_tutorial_4(&$form_state) {
  $form['description'] = array(
    '#type' => 'item',
    '#title' => t('A form with validation'),
  );

  $form['name'] = array(
    '#type' => 'fieldset',
    '#title' => t('Name'),
    // Make the fieldset collapsible.
    '#collapsible' => TRUE, // Added
    '#collapsed' => FALSE,  // Added
  );

  // Make these fields required.
  $form['name']['first'] = array(
    '#type' => 'textfield',
    '#title' => t('First name'),
    '#required' => TRUE, // Added
  );
  $form['name']['last'] = array(
    '#type' => 'textfield',
    '#title' => t('Last name'),
    '#required' => TRUE, // Added
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  return $form;
}


//////////////// Tutorial Example 5 //////////////////////

/**
 * Example 5: Basic form with additional element attributes.
 *
 * This demonstrates additional attributes of text form fields.
 *
 * For a more extensive example on element types
 * @see http://drupal.org/node/751826
 *
 * See the complete form reference at
 * @see http://api.drupal.org/api/file/developer/topics/forms_api.html

 */
function form_example_tutorial_5(&$form_state) {
  $form['description'] = array(
    '#type' => 'item',
    '#title' => t('A form with additional attributes'),
    '#description' => t('This one adds #default_value and #description'),
  );
  $form['name'] = array(
    '#type' => 'fieldset',
    '#title' => t('Name'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );

  $form['name']['first'] = array(
    '#type' => 'textfield',
    '#title' => t('First name'),
    '#required' => TRUE,
    '#default_value' => "First name", // added default value.
    '#description' => "Please enter your first name.", // added description
    '#size' => 20, // added
    '#maxlength' => 20, // added
  );
  $form['name']['last'] = array(
    '#type' => 'textfield',
    '#title' => t('Last name'),
    '#required' => TRUE,
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  return $form;
}


//////////////// Tutorial Example 6 //////////////////////

/**
 * Example 6: A basic form with a validate handler.
 *
 * From http://drupal.org/node/717736
 */

function form_example_tutorial_6(&$form_state) {
  $form['description'] = array(
    '#type' => 'item',
    '#title' => t('A form with a validation handler'),
  );

  $form['name'] = array(
    '#type' => 'fieldset',
    '#title' => t('Name'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );
  $form['name']['first'] = array(
    '#type' => 'textfield',
    '#title' => t('First name'),
    '#required' => TRUE,
    '#default_value' => "First name",
    '#description' => "Please enter your first name.",
    '#size' => 20,
    '#maxlength' => 20,
  );
  $form['name']['last'] = array(
    '#type' => 'textfield',
    '#title' => t('Last name'),
    '#required' => TRUE,
  );

  // New form field added to permit entry of year of birth.
  // The data entered into this field will be validated with
  // the default validation function.
  $form['year_of_birth'] = array(
    '#type' => 'textfield',
    '#title' => "Year of birth",
    '#description' => 'Format is "YYYY"',
  );

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  return $form;
}



/**
 * Now we add a handler/function to validate the data entered into the
 * "year of birth" field to make sure it's between the values of 1900
 * and 2000. If not, it displays an error. The value report is
 * $form_state['values'] (see http://drupal.org/node/144132#form-state).
 *
 * Notice the name of the function. It is simply the name of the form
 * followed by '_validate'. This is always the name of the default validation
 * function. An alternate list of validation functions could have been provided
 * in $form['#validate'].
 */
function form_example_tutorial_6_validate($form, &$form_state) {
  $year_of_birth = $form_state['values']['year_of_birth'];
  if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
    form_set_error('year_of_birth', 'Enter a year between 1900 and 2000.');
  }
}



//////////////// Tutorial Example 7 //////////////////////

/**
 * Example 7: With a submit handler.
 *
 * From the handbook page:
 * http://drupal.org/node/717740
 */

function form_example_tutorial_7($form_state) {
  $form['description'] = array(
    '#type' => 'item',
    '#title' => t('A form with a submit handler'),
  );
  $form['name'] = array(
    '#type' => 'fieldset',
    '#title' => t('Name'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );
  $form['name']['first'] = array(
    '#type' => 'textfield',
    '#title' => t('First name'),
    '#required' => TRUE,
    '#default_value' => "First name",
    '#description' => "Please enter your first name.",
    '#size' => 20,
    '#maxlength' => 20,
  );
  $form['name']['last'] = array(
    '#type' => 'textfield',
    '#title' => t('Last name'),
    '#required' => TRUE,
  );
  $form['year_of_birth'] = array(
    '#type' => 'textfield',
    '#title' => "Year of birth",
    '#description' => 'Format is "YYYY"',
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  return $form;
}


/**
 * Validation function.
 */
function form_example_tutorial_7_validate($form, &$form_state) {
    $year_of_birth = $form_state['values']['year_of_birth'];
    if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
        form_set_error('year_of_birth', 'Enter a year between 1900 and 2000.');
    }
}

/**
 * Adds a submit handler/function to our form to send a successful
 * completion message to the screen.
 */

function form_example_tutorial_7_submit($form, &$form_state) {
    drupal_set_message(t('The form has been submitted. name="@first @last", year of birth=@year_of_birth',
      array('@first' => $form_state['values']['first'], '@last' => $form_state['values']['last'], '@year_of_birth' => $form_state['values']['year_of_birth'])));
}


//////////////// Tutorial Example 8 //////////////////////

/**
 * Example 8: With a "reset" button.
 *
 * From handbook page http://drupal.org/node/717742.
 */
function form_example_tutorial_8(&$form_state) {
  $form['description'] = array(
    '#type' => 'item',
    '#title' => t('A form with a "reset" button'),
  );

  $form['name'] = array(
    '#type' => 'fieldset',
    '#title' => t('Name'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );

  // Removes the #required property and
  // uses the validation function instead.
  $form['name']['first'] = array(
    '#type' => 'textfield',
    '#title' => t('First name'),
    '#default_value' => "First name",
    '#description' => "Please enter your first name.",
    '#size' => 20,
    '#maxlength' => 20,
  );

  // Removes the #required property and
  // uses the validation function instead.
  $form['name']['last'] = array(
    '#type' => 'textfield',
    '#title' => t('Last name'),
  );
  $form['year_of_birth'] = array(
    '#type' => 'textfield',
    '#title' => "Year of birth",
    '#description' => 'Format is "YYYY"',
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  // Adds a new button to clear the form. The #validate property
  // directs the form to use a validation handler function specific
  // to this button instead of using the default handler.
  $form['clear'] = array(
    '#type' => 'submit',
    '#value' => 'Reset form',
    '#validate' => array('form_example_tutorial_8_clear'),
  );

  return $form;
}

/**
 * Validation function for the reset button.
 *
 * Setting the $form_state['rebuild'] value to TRUE says that we're going to
 * rebuild the form.  We also clear the existing values, although values
 * aren't used in the form builder in this example.
 */
function form_example_tutorial_8_clear($form, &$form_state) {
    $form_state['rebuild'] = TRUE;
    unset($form_state['values']);
}

/**
 * Makes the first and last name fields required by using the
 * validation function to make sure values have been entered. This
 * causes the name fields to show up in red if left blank after clearing
 * the form with the "Reset form" button.
 *
 * In a more extensive form, a validation function can check interdependencies
 * between fields. For example, it might be OK to enter only a last name, but
 * if you entered a last name you'd have to enter a first name.
 */
function form_example_tutorial_8_validate($form, &$form_state) {
    $year_of_birth = $form_state['values']['year_of_birth'];
    $first_name = $form_state['values']['first'];
    $last_name = $form_state['values']['last'];
    if (!$first_name) {
        form_set_error('first', 'Please enter your first name.');
    }
    if (!$last_name) {
        form_set_error('last', 'Please enter your last name.');
    }
    if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
        form_set_error('year_of_birth', 'Enter a year between 1900 and 2000.');
    }
}

function form_example_tutorial_8_submit($form, &$form_state) {
  drupal_set_message(t('The form has been submitted. name="@first @last", year of birth=@year_of_birth',
    array('@first' => $form_state['values']['first'], '@last' => $form_state['values']['last'], '@year_of_birth' => $form_state['values']['year_of_birth'])));
}



//////////////// Tutorial Example 9 //////////////////////

/**
 * Example 9: A form with a dynamically added new fields.
 *
 * This example adds default values so that when the form is rebuilt,
 * the form will by default have the previously-entered values.
 *
 * From handbook page http://drupal.org/node/717746.
 */
function form_example_tutorial_9(&$form_state) {
  $form['description'] = array(
    '#type' => 'item',
    '#title' => t('A form with dynamically added new fields'),
  );

  $form['name'] = array(
    '#type' => 'fieldset',
    '#title' => t('Name'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );

  // Change/add the #default_value for the first name, last name, and
  // birth year to show their old values so when the "Add another name"
  //button is clicked, they will retain their values.
  $form['name']['first'] = array(
    '#type' => 'textfield',
    '#title' => t('First name'),
    '#default_value' => !empty($form_state['values']['first']) ? $form_state['values']['first'] : '', // changed
    '#description' => "Please enter your first name.",
    '#size' => 20,
    '#maxlength' => 20,
  );
  $form['name']['last'] = array(
    '#type' => 'textfield',
    '#title' => t('Last name'),
    '#default_value' => !empty($form_state['values']['last']) ? $form_state['values']['last'] : '', // added
  );
  $form['year_of_birth'] = array(
    '#type' => 'textfield',
    '#title' => "Year of birth",
    '#description' => 'Format is "YYYY"',
    '#default_value' => !empty($form_state['values']['year_of_birth']) ? $form_state['values']['year_of_birth'] : '', // added
  );

  // Add new elements to the form if $form_state['storage']['new_name'] is set.
  // This happens when the "add new name" button is clicked.
  if (isset($form_state['storage']['new_name'])) {
    $form['name2'] = array(
      '#type' => 'fieldset',
      '#title' => t('Name #2'),
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
    );
    $form['name2']['first2'] = array(
      '#type' => 'textfield',
      '#title' => t('First name'),
      '#description' => "Please enter your first name.",
      '#size' => 20,
      '#maxlength' => 20,
      '#default_value' => !empty($form_state['values']['first2']) ? $form_state['values']['first2'] : '',
    );
    $form['name2']['last2'] = array(
      '#type' => 'textfield',
      '#title' => t('Last name'),
      '#default_value' => !empty($form_state['values']['last2']) ? $form_state['values']['last2'] : '',
    );
    $form['year_of_birth2'] = array(
      '#type' => 'textfield',
      '#title' => "Year of birth",
      '#description' => 'Format is "YYYY"',
      '#default_value' => !empty($form_state['values']['year_of_birth2']) ? $form_state['values']['year_of_birth2'] : '',
    );
  }

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  $form['clear'] = array(
    '#type' => 'submit',
    '#value' => 'Reset form',
    '#validate' => array('form_example_tutorial_9_clear'),
  );

  // Adds "Add another name" button, if it hasn't already been clicked.
  if (empty($form_state['storage']['new_name'])) {
    $form['new_name'] = array(
      '#type' => 'submit',
      '#value' => 'Add another name',
      '#validate' => array('form_example_tutorial_9_new_name'),
    );
  }

  return $form;
}

/**
 * Creating a new element, 'new_name' in the $form_state['storage'] array
 * sets the value used to determine whether to show the new
 * fields on the form and hide the "Add another name" button.
 *
 * $form_state['storage'] is just a place to store spare information. Any
 * keys can be created in this array.
 */
function form_example_tutorial_9_new_name($form, &$form_state) {
    $form_state['storage']['new_name'] = TRUE;
    // Setting $form_state['rebuild'] = TRUE causes the default submit
    // function to be skipped and the form to be rebuilt.
    $form_state['rebuild'] = TRUE;
}

function form_example_tutorial_9_clear($form, &$form_state) {
  // Ensures fields are blank after the reset button is clicked.
  unset($form_state['values']);
  // Ensures the reset button removes the new_name button.
  unset($form_state['storage']);
  // Setting $form_state['rebuild'] = TRUE causes the default submit
  // function to be skipped and the form to be rebuilt.

  $form_state['rebuild'] = TRUE;
}

/**
 * Adds logic to validate the form to check the validity of the new fields,
 * if they exist.
 */
function form_example_tutorial_9_validate($form, &$form_state) {
  $year_of_birth = $form_state['values']['year_of_birth'];
  $first_name = $form_state['values']['first'];
  $last_name = $form_state['values']['last'];
  if (!$first_name) {
    form_set_error('first', 'Please enter your first name.');
  }
  if (!$last_name) {
    form_set_error('last', 'Please enter your last name.');
  }
  if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
    form_set_error('year_of_birth', 'Enter a year between 1900 and 2000.');
  }
  if ($form_state['storage']['new_name']) {
    $year_of_birth = $form_state['values']['year_of_birth2'];
    $first_name = $form_state['values']['first2'];
    $last_name = $form_state['values']['last2'];
    if (!$first_name) {
      form_set_error('first2', 'Please enter your first name.');
    }
    if (!$last_name) {
      form_set_error('last2', 'Please enter your last name.');
    }
    if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
      form_set_error('year_of_birth2', 'Enter a year between 1900 and 2000.');
    }
  }
}
/**
 * Submit function.
 *
 * Commenting out unset($form_state['storage'] and
 * then adding a new set of name fields and submitting the form,
 * would cause the form to rebuilt with the existing values, because in
 * Drupal 6 if $form_state['storage'] is set, $form_state['rebuild'] is also
 * automatically set, causing the form fields to get rebuilt with the
 * values found in $form_state['values'].
 */
function form_example_tutorial_9_submit($form, &$form_state) {
  unset($form_state['storage']);
  drupal_set_message(t('The form has been submitted. name="@first @last", year of birth=@year_of_birth',
    array('@first' => $form_state['values']['first'], '@last' => $form_state['values']['last'], '@year_of_birth' => $form_state['values']['year_of_birth'])));
  if (!empty($form_state['values']['first2'])) {
      drupal_set_message(t('Second name: name="@first @last", year of birth=@year_of_birth',
    array('@first' => $form_state['values']['first2'], '@last' => $form_state['values']['last2'], '@year_of_birth' => $form_state['values']['year_of_birth2'])));
  }
}



//////////////// Tutorial Example 10 //////////////////////

/**
 * Example 10: A simple multistep form.
 *
 * Handbook page: http://drupal.org/node/717750.
 *
 * For more extensive multistep forms,
 * @see http://pingvision.com/blog/ben-jeavons/2009/multi-step-forms-drupal-6-using-variable-functions
 *
 */

/**
 * Adds logic to our form builder to give it two pages. It checks a
 * value in $form_state['storage'] to determine if it should display page 2.
 */
function form_example_tutorial_10($form_state) {

  // Display page 2 if $form_state['storage']['page_two'] is set
  if (isset($form_state['storage']['page_two'])) {
    return form_example_tutorial_10_page_two();
  }
  $form['description'] = array(
    '#type' => 'item',
    '#title' => t('A basic multistep form (page 1)'),
  );

  // Page 1 is displayed if $form_state['storage']['page_two'] is not set
  $form['name'] = array(
    '#type' => 'fieldset',
    '#title' => t('Name'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );
  $form['name']['first'] = array(
    '#type' => 'textfield',
    '#title' => t('First name'),
    '#default_value' => !empty($form_state['values']['first']) ? $form_state['values']['first'] : '', // changed
    '#description' => "Please enter your first name.",
    '#size' => 20,
    '#maxlength' => 20,
  );
  $form['name']['last'] = array(
    '#type' => 'textfield',
    '#title' => t('Last name'),
    '#default_value' => !empty($form_state['values']['last']) ? $form_state['values']['last'] : '', // added
  );
  $form['year_of_birth'] = array(
    '#type' => 'textfield',
    '#title' => "Year of birth",
    '#description' => 'Format is "YYYY"',
    '#default_value' => !empty($form_state['values']['year_of_birth']) ? $form_state['values']['year_of_birth'] : '', // added
  );
  // Add new elements to the form
  if (!empty($form_state['storage']['new_name'])) {
    $form['name2'] = array(
      '#type' => 'fieldset',
      '#title' => t('Name #2'),
      '#collapsible' => TRUE,
      '#collapsed' => FALSE,
    );
    $form['name2']['first2'] = array(
      '#type' => 'textfield',
      '#title' => t('First name'),
      '#description' => "Please enter your first name.",
      '#size' => 20,
      '#maxlength' => 20,
      '#default_value' => !empty($form_state['values']['first2']) ? $form_state['values']['first2'] : '',
    );
    $form['name2']['last2'] = array(
      '#type' => 'textfield',
      '#title' => t('Last name'),
      '#default_value' => !empty($form_state['values']['last2']) ? $form_state['values']['last2'] : '',
    );
    $form['year_of_birth2'] = array(
      '#type' => 'textfield',
      '#title' => "Year of birth",
      '#description' => 'Format is "YYYY"',
      '#default_value' => !empty($form_state['values']['year_of_birth2']) ? $form_state['values']['year_of_birth2'] : '',
    );
  }
  $form['clear'] = array(
    '#type' => 'submit',
    '#value' => 'Reset form',
    '#validate' => array('form_example_tutorial_10_clear'),
  );
  if (empty($form_state['storage']['new_name'])) {
    $form['new_name'] = array(
      '#type' => 'submit',
      '#value' => 'Add another name',
      '#validate' => array('form_example_tutorial_10_new_name'),
    );
  }
  $form['next'] = array(
    '#type' => 'submit',
    '#value' => 'Next >>',
  );
  return $form;
}

// New function created to help make the code more manageable.
function form_example_tutorial_10_page_two() {
  $form['description'] = array(
    '#type' => 'item',
    '#title' => t('A basic multistep form (page 2)'),
  );

  $form['color'] = array(
    '#type' => 'textfield',
    '#title' => 'Your favorite color',
  );
  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => 'Submit',
  );
  return $form;
}

function form_example_tutorial_10_new_name($form, &$form_state) {
  $form_state['storage']['new_name'] = TRUE;
  $form_state['rebuild'] = TRUE; // default submit function will be skipped
}

function form_example_tutorial_10_clear($form, &$form_state) {
  unset($form_state['values']);
  unset($form_state['storage']);

  $form_state['rebuild'] = TRUE;
}

/**
 * The validate function now validates page 2 as well.
 */
function form_example_tutorial_10_validate($form, &$form_state) {
  // Validate page 2 here
  if (isset($form_state['storage']['page_two'])) {
    $color = $form_state['values']['color'];
    if (!$color) {
      form_set_error('color', 'Please enter a color.');
    }
    return;
  }

  $year_of_birth = $form_state['values']['year_of_birth'];
  $first_name = $form_state['values']['first'];
  $last_name = $form_state['values']['last'];
  if (!$first_name) {
    form_set_error('first', 'Please enter your first name.');
  }
  if (!$last_name) {
    form_set_error('last', 'Please enter your last name.');
  }
  if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
    form_set_error('year_of_birth', 'Enter a year between 1900 and 2000.');
  }
  if ($form_state['storage']['new_name']) {
    $year_of_birth = $form_state['values']['year_of_birth2'];
    $first_name = $form_state['values']['first2'];
    $last_name = $form_state['values']['last2'];
    if (!$first_name) {
      form_set_error('first2', 'Please enter your first name.');
    }
    if (!$last_name) {
      form_set_error('last2', 'Please enter your last name.');
    }
    if ($year_of_birth && ($year_of_birth < 1900 || $year_of_birth > 2000)) {
      form_set_error('year_of_birth2', 'Enter a year between 1900 and 2000.');
    }
  }
}

/**
 * Modifies this function so that it will respond appropriately based on
 * which page was submitted. If the first page is being submitted,
 * values in the 'storage' array are saved and the form gets
 * automatically reloaded.
 *
 * If page 2 was submitted, we display a message and redirect the
 * user to another page.
 */
function form_example_tutorial_10_submit($form, &$form_state) {
  // Handle page 1 submissions
  if ($form_state['clicked_button']['#id'] == 'edit-next') {
    $form_state['storage']['page_two'] = TRUE; // We set this to determine
                                               // which elements to display
                                               // when the page reloads.

    // Values below in the $form_state['storage'] array are saved
    // to carry forward to subsequent pages in the form.
    $form_state['storage']['page_one_values'] = $form_state['values'];
  }
  // Handle page 2 submissions.
  else {
    /*
     Normally, some code would go here to alter the database with the data
     collected from the form. Sets a message with drupal_set_message()
     to validate working code.
     */
    $page_one_values = $form_state['storage']['page_one_values'];
    drupal_set_message(t('The form has been submitted. name="@first @last", year of birth=@year_of_birth',
      array('@first' => $page_one_values['first'], '@last' => $page_one_values['last'], '@year_of_birth' => $page_one_values['year_of_birth'])));

    if (!empty($page_one_values['first'])) {
      $first2 = isset($page_one_values['first2']) ? $page_one_values['first2'] : '';
      $last2  = isset($page_one_values['last2']) ? $page_one_values['last2'] : '';
      $year2  = isset($page_one_values['year_of_birth2']) ? $page_one_values['year_of_birth2'] : '';
      drupal_set_message(t('Second name: name="@first @last", year of birth=@year_of_birth',
        array('@first' => $first2, '@last' => $last2, '@year_of_birth' => $year2)));
    }
    drupal_set_message(t('And the favorite color is @color', array('@color' => $form_state['values']['color'])));

    // $form_state['storage'] must be unset for redirection to occur. Otherwise
    // $form_state['rebuild'] is automatically set and this form will be
    // rebuilt.
    unset($form_state['storage']);
    $form_state['redirect'] = 'node'; // Redirects the user to /node.
  }
}

//////////////// Tutorial Example 11 //////////////////////

/**
 * Example 11: A form with a file upload field.
 *
 * This example allows the user to upload a file to Drupal which is stored
 * physically and with a reference in the database. In this example, only
 * png, gif, jpg, and jpeg files are allowed.
 *
 * @see form_example_tutorial_11_validate()
 * @see form_example_tutorial_11_submit()
 * @ingroup form_example
 *
 */
function form_example_tutorial_11($form_state) {
  // This is required to upload files.
  // enctype="multipart/form-data" required by browsers to handle files.
  $form = array(
    '#attributes' => array('enctype' => "multipart/form-data"),
  );

  $form['file'] = array(
    '#type' => 'file',
    '#title' => t('Image'),
    '#description' => t('Upload a file, allowed extensions: jpg, jpeg, png, gif'),
  );

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

  return $form;
}

/**
 * Validate handler for form_example_tutorial_11().
 * Verify the valid extensions, and verify content is an image also.
 */
function form_example_tutorial_11_validate($form, &$form_state) {
  $file = file_save_upload('file', array(
    'file_validate_extensions' => array('png gif jpg jpeg'),
    'file_validate_is_image' => array(),
  ));
  
  // If the file passed validation:
  if (isset($file->filename)) {
    // Move the file, into the Drupal file system
    if (file_move($file, $file->filename)) {
      // Update the new file location in the database.
      drupal_write_record('files', $file, 'fid');
      // Save the file for use in the submit handler.
      $form_state['storage']['file'] = $file;
    }
    else {
      form_set_error('file', t('Failed to write the uploaded file the site\'s file folder.'));
    }
  }
  else {
    form_set_error('file', t('Invalid file, only images with the extension png, gif, jpg, jpeg are allowed'));
  }
}

/**
 * Submit handler for form_example_tutorial_11().
 */
function form_example_tutorial_11_submit($form, &$form_state) {
  $file = $form_state['storage']['file'];
  // We are done with the file, remove it from storage.
  unset($form_state['storage']['file']);
  // Make the storage of the file permanent
  file_set_status($file, FILE_STATUS_PERMANENT);
  // Set a response to the user.
  drupal_set_message(t('The form has been submitted and the image has been saved, filename: @filename.', array('@filename' => $file->filename)));
}


来自 http://alvinalexander.com/drupal-code-examples/drupal-6-examples-module/form_example/form_example_tutorial.inc.shtml


 

File uploads in Drupal 6 - Part 1



So you've got a nice new version of Drupal 6 and you're building a form, but you want to allow users to upload a file. Of course this is easy with Drupal, and we covered how to do just that, but for Drupal 5, in our previous article: Example code to build an upload form in Drupal. Here we show how file uploads are done in Drupal 6.

Honestly, not much has changed, here's the code to get your file upload element onto your form:

function build_upload_form(){
    $form['#attributes'] = array('enctype' => 'multipart/form-data');
    $form['file_upload'] = array(
        '#type' => 'file',
        '#title' => 'Filename'
    );
    $form['submit'] = array(
        '#type' => 'submit',
        '#value' => 'Upload file'
    );
    return $form;
}

Nothing has changed since Drupal 5 there, but the changes come in the submit function:

function upload_form_submit($form, &amp;$form_state) {

  //define your limits for the submission here
  $limits = array ( ... ) ;

  $validators = array(
    'file_validate_extensions' => array($limits['extensions']),
    'file_validate_image_resolution' => array($limits['resolution']),
    'file_validate_size' => array(
        $limits['file_size'], 
        $limits['user_size']
    ),
  );

  // Save new file uploads.
  if ($file = file_save_upload('file_upload', $validators, file_directory_path())) {
    // Do something with $file here.
  }
}

We have a big change here, we can define an array of file validation functions to pass tofile_save_upload and only if the file conforms to those will it be saved.

File validation functions:

These are simply functions that receive the $file object as their first parameter and extra parameters as defined in your invocation of file_save_upload(). Drupal core comes with four:

  1. file_validate_extensions() checks that the file extension in the given list

  2. file_validate_size() checks for maximum file sizes and against a user's quota

  3. file_validate_is_image() checks that the upload is an image

  4. file_validate_image_resolution() checks that images meets maximum and minimum resolutions requirements.

You can always write your own to check extra things, you just need to return an array of error messages if there are any, and an empty array if not. More information can be found in the Drupal handbook.

Next Steps

We're not going to cover what you could do with your uploaded and validated file object, but there is one obvious thing that you might want to do before all that: AJAX uploading.
Drupal's core upload module allows you to upload files to nodes, and provides a nice 'attach' button which starts the upload process in the background leaving users free to fill in the rest of the form, doing this with your own forms turns out to be quite challenging, as we shall see in the next part of this tutorial!
 

Comments

Nice post, looking forward to the AJAX version :)

Yes, very interesting article, thanks!

Thanks for a really useful tutorial - so where's part 2? or did you decide to cheat and just integrate SWFUpload or something similar with your drupal?

Thanks, really looking forward to the AJAX version, any idea when you're goin to publish that one?

I have same problem with Arek, the upload doesn't work and there's no error statement.. Help please.. Thx..

thanks such a grate post

thanks a lot

thanks such a grate post

thanks a lot

One thing I've noticed in D6 with file uploads is that using only file_save_upload() will result in your file being purged on a subsequent drupal cron run. This happens because all files are uploaded in Drupal with a status of 0.

Therefore, you should be calling your hook_submit more like this...

// Save new file uploads.
if ($file = file_save_upload('file_upload', $validators, file_directory_path())) {

// Do something with $file here.

//Make file permanent
file_set_status($file, FILE_STATUS_PERMANENT);
}

Hopefully this helps someone. I spent a bit of time on this before I really understood why my files were disappearing.

should this

// Save new file uploads.
if ($file = file_save_upload('upload', $validators, file_directory_path())) {
// Do something with $file here.
}

be

// Save new file uploads.
if ($file = file_save_upload('file_upload', $validators, file_directory_path())) {
// Do something with $file here.
}

Isn't hook_submit deprecated (or even left out) of drupal 6?

hello,

thanks for this nice artcile. it would be great if you could explain about how to use file_validate_extensions or simillar file functions as stand alone unlike you used it in file_save_upload() function.

Thanks in advance

please note that there's a small bug in the posted sample code above, as pointed out by errata

in the build_upload_form() function, the name of the upload field is "file_upload", but in the upload_form_submit() function you refer to the uploaded file as though the file upload field was named "upload"

file_save_upload('upload', $validators, file_directory_path())

that won't work - needs to be

file_save_upload('file_upload', $validators, file_directory_path())

Thank you errata, xurizaemon! I have edited the post. Cheers, G

Hi i have read some comments regards ajax version.

But as i knw file upload is not support by ajax. right ?????

Shail

You can use AHAH to do file uploads, as core does it. I'll get around to writing part 2 of this tutorial at some point, and you'll see how!

If you could put valued in the $limits array it would have been great. There is some confusions on how it works. :)

test

it works great

what about uploading multiple files?

it is not working for me. when I push upload button it looks like file is being uploaded but it is not saved anywhere. there is not of any errors so I don't know what is wrong :(

Comments on this article are now closed, if you want to give us feeback you can use our contact form instead.



来自  https://www.computerminds.co.uk/file-uploads-drupal-6-part-1

http://alvinalexander.com/drupal-code-examples/drupal-6-examples-module/form_example/form_example_tu...

 


普通分类: