Location: PHPKode > scripts > B-Forms > b-forms/upload.inc
<?

/* -------------------------------------------------------------

    B-Forms / Upload
    An object-oriented library to manage web-forms in PHP.
    An extention to handle file uploads.

    Copyright (C) 2004 Alexei Peterkin, hide@address.com

    This library is free software; you can redistribute it
    and/or modify it under the terms of the GNU Lesser General
    Public License as published by the Free Software
    Foundation; either version 2.1 of the License, or (at your
    option) any later version.

    This library is distributed in the hope that it will be
    useful, but WITHOUT ANY WARRANTY; without even the implied
    warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
    PURPOSE. See the GNU Lesser General Public License for more
    details.

    You should have received a copy of the GNU Lesser General
    Public License along with this library; if not, write to
    the Free Software Foundation, Inc., 59 Temple Place, Suite
    330, Boston, MA 02111-1307 USA

-------------------------------------------------------------- */


/**
 * Experimental display for {@link FileProperty}
 */
class FileUpload extends Display {
   var $extras;
   var $clear_text;

   function FileUpload($extras="", $clear_text="Clear file") {
      $this->extras = $extras;
      $this->clear_text = $clear_text;
   }

   function show($property, $rownum = -1) {
      // We need to save status data
      // Saving last_saved_name
      echo "<input type=\"hidden\" name=\"".
           $property->get_form_name($rownum)."__saved".
           "\" value=\"".
           htmlspecialchars($property->get_last_saved($rownum)).
           "\"/>\n";
      // Saving last_uploaded_name
      echo "<input type=\"hidden\" name=\"".
           $property->get_form_name($rownum)."__uploaded".
           "\" value=\"".
           htmlspecialchars($property->get_last_uploaded($rownum)).
           "\"/>\n";
      // Now we need to display the old value
      $property->file_display->show($property, $rownum);
      // Now we need to display the upload thingey
      echo "<br/><input type=\"file\" name=\"".
           $property->get_form_name($rownum).
           "\" ".$this->extras."/>\n";
      // Now we need to display the clear checkbox (if needed)
      if ($property->allow_clear)
         echo "<br/><input type=\"checkbox\" name=\"".
            $property->get_form_name($rownum).
            "__clear\" value=\"Y\"/> ".$this->clear_text."\n";
   }
}

/**
 * Experimental display for {@link FileProperty}
 */
class ImageNameDisplay extends Display {
    var $extras;
    var $noimage_text;
    var $final_base;
    var $intermediate_base;

    function ImageNameDisplay($final_base, $intermediate_base, $extras, $noimage_text="No image") {
       $this->extras = $extras;
       $this->noimage_text = $noimage_text;
       $this->final_base = $final_base;
       $this->intermediate_base = $intermediate_base;
    }

    function show($property, $rownum = -1) {
       echo "<table border=\"0\" cellspacing=\"0\" cellpadding=\"0\"><tr><td align=\"center\">\n";
       if ($property->get_value($rownum) == "") {
          echo $this->noimage_text;
       }
       else {
          if ($property->get_last_uploaded($rownum) != "")
             $name = $this->intermediate_base.'/'.
                        $property->get_file_name($property->get_last_uploaded($rownum),$rownum);
          else
             $name = $this->final_base.'/'.
                        $property->get_file_name($property->get_last_saved($rownum), $rownum);
          echo "<img src=\"".$name."\" border=\"0\"/></td></tr><tr><td align=\"center\" ".$this->extras.">\n";
          echo $property->get_value($rownum);
       }
       echo "</td></tr></table>\n";
    }
}

// File upload property has many states, and thus is a very complex widget.
// States (at the moment of diplaying the form):
//  - empty:  no file has been loaded
//  - unchanged: file loaded at previous edit operation is still valid
//  - replaced: a new file has been loaded into the form, however not yet saved
//  - repeatedly replaced: a new file has been loaded into the form, which relaces another new file loaded into the form,
//                         none of which have been saved.
//  - new, repeatedly new - same as replaced and repeately replaced, but fist time load.
// Operations that can be performed on the field:
//  - select new file (and upload) - this changes the state
//  - clear selected file - what happens depends on the state
// To represent this stuff we need a few parameters (kept by the form, or retrieved from the database all the time):
//  - last saved filename
//  - last uploaded filename
//  - current filename (which is different from the file input, since this is how we are going to transfer the info that
//                      the file need to be cleared)
// To do all of this we need to know:
//  - directory for intermediate files (repeatedly replaced)
//  - directory for final files
//  - naming rules (how the file should be saved)
//  - do we support file clearing
//  - how do we display the current file (name or the actual image) - basically a special nested display element.
// For now let's decide, that naming rules are the following:
//  - objectid_propertyname_[nrow_]origfilename.

/**
 * Experimental property for uploading files.
 */
class FileProperty extends Property {
   // Operational attributes
   var $last_saved_name; // Could be an array if multirow
   var $last_uploaded_name; // Could be an array if multirow
   // Plus current value in the block

   // Configuration attributes
   var $intermediate_location;
   var $final_location;
   var $allow_clear; // Boolean
   var $file_display; // Element that displays the current file.

   function FileProperty($name, $label, $required,
                         $intermediate_location, $final_location, $allow_clear, $file_display) {
      parent::Property($name, $label, "", $required);
      $this->intermediate_location = $intermediate_location;
      $this->final_location = $final_location;
      $this->allow_clear = $allow_clear;
      $this->file_display = $file_display;
   }

   function get_default_display() {
      return new FileDisplay();
   }

   function get_last_saved($rownum = -1) {
      if ($rownum > 0)
         return $this->last_saved_name[$rownum];
      else
         return $this->last_saved_name;
   }

   function set_last_saved($value, $rownum = -1) {
      if ($rownum > 0)
         $this->last_saved_name[$rownum] = $value;
      else
         $this->last_saved_name = $value;
   }

   function get_last_uploaded($rownum = -1) {
      if ($rownum > 0)
         return $this->last_uploaded_name[$rownum];
      else
         return $this->last_uploaded_name;
   }

   function set_last_uploaded($value, $rownum = -1) {
      if ($rownum > 0)
         $this->last_uploaded_name[$rownum] = $value;
      else
         return $this->last_uploaded_name = $value;
   }

   function get_file_name($name, $rownum = -1) {
      // by format objectid_propertyname_[nrow_]origfilename
      if ($rownum>0)
         $objectid = $this->block->id[$rownum];
      else
         $objectid = $this->block->id;
      $result = $objectid."_".$this->name;
      if ($rownum > 0)
         $result .= "_".$rownum;
      return $result."_".$name;
   }

   function form_read($rownum = -1) {
      global $_FILES;
      $n = $this->get_form_name($rownum);

      // First, let's restore old parameters
      $this->set_last_saved($this->strip_post_var($n."__saved"), $rownum);
      $this->set_last_uploaded($this->strip_post_var($n."__uploaded"), $rownum);

      if ($_FILES[$n]['name'] != "") {
         // Let us store the filename into the value of the property
         $this->set_value($_FILES[$n]['name'], $rownum);
      }
      else { // There was no new upload
         if ($this->strip_post_var($n."__clear")=="Y") {
            $this->set_value("", $rownum);
         }
         else {  // File unchanged
            if ($this->get_last_uploaded($rownum) != "")
               $this->set_value($this->get_last_uploaded($rownum));
            else
               $this->set_value($this->get_last_saved($rownum));
         }
      }

      // Now we need to do some file movements.
      // If new file has been uploaded, then we need to move it to the intermediate directory.  If this was a
      // repeated replace then we need to remove old file.
      // If we want to clear file that was uploaded, then we need to clear the file in the intermediate directory

      if ($_FILES[$n]['name'] != "" || $this->strip_post_var($n."__clear")=="Y") {

         // First, if there was an old uploaded file, we need to delete it
         if ($this->get_last_uploaded($rownum) != "") {
            @unlink($this->intermediate_location.'/'.
                      $this->get_file_name($this->get_last_uploaded($rownum), $rownum));
         }

         // Now, if there is new uploaded file, then we need to move it to the intermediate location
         if ($this->get_value($rownum) != "") {
            // To avoid file exists probles, we first unlink the target location
            @unlink($this->intermediate_location.'/'.
                                  $this->get_file_name($this->get_value($rownum), $rownum));
            move_uploaded_file($_FILES[$n]['tmp_name'],
                               $this->intermediate_location.'/'.
                                  $this->get_file_name($this->get_value($rownum), $rownum));
         }

         $this->set_last_uploaded($this->get_value($rownum),$rownum);
      }
   }

   function save_file($idold, $idnew, $rownum = -1) {
      // If the current value is different from the last saved value, then we need to move file, not forgetting to
      // delete the old unneeded file.
      // PROBLEM:  will not work, if last saved and current filenames are the same, but the contents of the file have changed
      // ALSO: We cannot use function get_file_name since ids may have changed

      if ($this->get_last_saved($rownum) != $this->get_value($rownum)) {

         $row = ($rownum > 0)?"_$rownum":"";

         // First, if there was an old saved file, we need to delete it
         if ($this->get_last_saved($rownum) != "") {
            // If id has changed, by now the file has been renamed to reflect new id
            @unlink($this->final_location.'/'.$idnew.'_'.$this->name.$row.'_'.$this->get_last_saved($rownum));
         }

         // Now, if there is new uploaded file, then we need to move it to the intermediate location
         if ($this->get_value($rownum) != "") {
            // To avoid file exists problems, we first unlink the target location
            @unlink($this->final_location.'/'.$idnew.'_'.$this->name.$row.'_'.$this->get_value($rownum));

            rename($this->intermediate_location.'/'.$idold.'_'.$this->name.$row.'_'.$this->get_last_uploaded($rownum),
                   $this->final_location.'/'.$idnew.'_'.$this->name.$row.'_'.$this->get_value($rownum));
         }
      }
   }

   function init($filename, $rownum = -1) {
      $this->set_value($filename, $rownum);
      $this->set_last_saved($filename, $rownum);
   }

   function get_sql_value($rownum = -1) {
      $value = parent::get_sql_value($rownum);
      return ($value=="") ? "null" : "'$value'";
   }

   function is_multipart() {
      return TRUE;
   }

}

?>
Return current item: B-Forms