Attached Files

From Zen Cart(tm) Wiki
Jump to: navigation, search

Overview

I wanted a way of attaching files to a product - these files could be PDFs with specifications, user manuals or software patches.


This is a hack that provides that functionality for anyone interested.


There are basically three parts to the code


  1. Create a database table to store the information.
  2. Provdie an Admin interface to attach and delete files.
  3. Display this attached files and provide a way to download these files to the end user.


In this case, I am not providing any security as to what attached files are displayed or downloaded. This is different from several posts I have read where people what to charge based on these files.


Database

I have elected to store the entire file contents in the database at this stage.


  CREATE TABLE `zen_products_file` (
    `products_file_id` int(11) NOT NULL auto_increment,
    `products_id` int(11) NOT NULL default '0',
    `products_file_name` varchar(100) NOT NULL default '',
    `products_file_filename` varchar(100) NOT NULL default '',
    `products_file_type` varchar(100) NOT NULL default '',
    `products_file_data` longblob NOT NULL,
    PRIMARY KEY  (`products_file_id`),
    KEY `products_id` (`products_id`),
    KEY `products_file_name` (`products_file_name`)
    );


Admin Area

Here I have modified the core files in the Admin section.


Product Collect Data

I want to display all the currently attached files (with and option to delete) as well as three options to upload new files.

  • /admin/includes/modules/products/collect_info.php


Insert this text just after the Sort Order option.

          <tr>
            <td colspan="2"><?php echo zen_draw_separator('pixel_trans.gif', '1', '10'); ?></td>
          </tr>
          <tr>
            <td class="main">Attached Files</td>
            <td class="main"></td>
          </tr>
<?

  $files = $db->Execute("select * from zen_products_file where (products_id = '".(int)$_GET['pID']."') order by products_file_name");
  while (!$files->EOF) {
?>
          <tr>
            <td class="main"></td>
            <td class="main"><? echo zen_draw_separator('pixel_trans.gif', '24', '15') . ' ' 
              . zen_draw_input_field("product_file_name[" . $files->fields['products_file_id'] ."]", $files->fields['products_file_name']); ?></td>
          </tr>
<?

    $files->MoveNext();
    }

?>
          <tr>
            <td class="main"></td>
            <td class="main"><? echo zen_draw_separator('pixel_trans.gif', '24', '15') . ' ' . zen_draw_file_field('products_file_1'); ?></td>
          </tr>
          <tr>
            <td class="main"></td>
            <td class="main"><? echo zen_draw_separator('pixel_trans.gif', '24', '15') . ' ' . zen_draw_file_field('products_file_2'); ?></td>
          </tr>
          <tr>
            <td class="main"></td>
            <td class="main"><? echo zen_draw_separator('pixel_trans.gif', '24', '15') . ' ' . zen_draw_file_field('products_file_3'); ?></td>
          </tr>


Product Preview Data

  • /admin/includes/modules/products/preview_info.php


Here I am doing the work - in reality, I should be displaying the changes and doing the mods as part of the Update page - but I am not sre how to integrate that at this point.


Add this text after the main body text is displayed

      <tr>
        <td><?
        
        function processnew ($varname) {
          $newfile = $_FILES[$varname];
          if (isset($newfile) and ($newfile["error"] == 0)) {
            unset($ins);
            $ins['products_file_filename'] = zen_db_prepare_input($newfile['name']);
            $ins['products_file_name'] = zen_db_prepare_input($newfile['name']);
            $ins['products_file_type'] = zen_db_prepare_input($newfile['type']);
            $ins['products_id'] = zen_db_prepare_input( (int)$_GET['pID'] );
            $ins['products_file_data'] = zen_db_prepare_input(File_Get_Contents($newfile['tmp_name']));        
            $ins['products_file_data'] = gzcompress($ins['products_file_data']);        
            zen_db_perform("zen_products_file", $ins);
            }
          }
        
        
        processnew('products_file_1');
        processnew('products_file_2');
        processnew('products_file_3');
        
        
        $productnames = $_POST["product_file_name"];
        if (is_array($productnames)) {
          foreach ($productnames as $pfid => $pfname) {
            unset($upd);
            $upd['products_file_name'] = zen_db_prepare_input($pfname);
            // $upd['products_file_id'] = zen_db_prepare_input($pfid);
            zen_db_perform("zen_products_file", $upd, 'update', "products_file_id = '" . (int)$pfid . "'");
            }
          }
        
        
        $productdelete = $_POST["product_file_delete"];
        if (is_array($productdelete)) {
          foreach ($productnames as $pfid => $pfvalue) {
            
            $sql = "delete from zen_products_file where (products_file_id = $pfid)";
            $db->Execute($sql);

            }
          }
        
        
        
        $files = $db->Execute("select * from zen_products_file where (products_id = '".(int)$_GET['pID']."') order by products_file_name");      
        if ($files->RecordCount() == 0) {
          // if no attached files, there is no need to show anything
          // echo "No attached files";
          }
        else {
          echo "<p><b>Attached Files</b></p>";
          echo "<ul>";
          while (!$files->EOF) {
            echo "<li>".$files->fields['products_file_name']."</li>";
            $files->MoveNext();
            }
          echo "</ul>";
          }        
        
        
        ?></td>
      </tr>


Product Update Data

This is where the actual changes should be implmented.


User Area

Need to

  1. List the files
  2. link to the file and provide a download


Product View

Here we can use a override file so as not to modify the core. Duplicate tis file from default_template.


  • /includes/template/YOURTEMPLATE/template/tpl_product_info_display.php


and add this code after the description (line 258). It create a list of attached files and links them to the download URL

<?php

        $files = $db->Execute("select * from zen_products_file where (products_id = '".(int)$_GET['products_id']."') order by products_file_name");      
        if ($files->RecordCount() == 0) {
          // if no attached files, there is no need to show anything
          // echo "No attached files";
          }
        else {
        
?>
  <tr>
    <td class="main" align="left" valign="top" colspan="2">
      <b>Attached Files</b>
      <ul>
<?php    

          while (!$files->EOF) {
            echo "<li><a href=\"index.php?main_page=attached_file&id=".$files->fields['products_file_id']."\">".$files->fields['products_file_name']."</a></li>";
            $files->MoveNext();
            }

?>  
      </ul>
    </td>     
  </tr>  
<?          
          } // there are files 
?>


Attached File Download

create this empty file


  • /includes/template/YOURTEMPLATE/template/tpl_attached_file_default.php


and create this file/path


  • /includes/modules/pages/attached_file/header_php.php


with this content


<?php

  $file = $db->Execute("select * from zen_products_file where (products_file_id = '".(int)$_GET['id']."')");      
  
  if ($file->RecordCount() == 0) {
    header("HTTP/1.0 404 Not Found");
    exit;
    }
  

  $filedata = $file->fields['products_file_data'];
  $filedata = gzuncompress($filedata);
  $filename = $file->fields['products_file_filename'];
  $filetype = $file->fields['products_file_type'];
  $filesize = StrLen($filedata);


  if (empty($filedata)) {
    header("HTTP/1.0 404 Not Found");
    exit;
    }

  header("Content-length: $filesize");
  header("Content-type: $filetype");
  header("Content-Disposition: \"attachment; filename=\"$filename\"\"");
  print $filedata;

  exit;  // don't want any more of page
  
  
?>