<?
/* -------------------------------------------------------------
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;
}
}
?>