JasonWoof Got questions, comments, patches, etc.? Contact Jason Woofenden
revamped uploaded image handling, added thumbnailing support to metaform
authorJason Woofenden <jason283@herkamire.com>
Thu, 28 May 2009 10:25:22 +0000 (06:25 -0400)
committerJason Woofenden <jason283@herkamire.com>
Thu, 28 May 2009 10:25:22 +0000 (06:25 -0400)
encode.php
format.php
metaform.php
metaform/template.html
metaform/template.php
upload.php

index 273d026..9aa09a6 100644 (file)
@@ -342,4 +342,31 @@ function enc_evenodd($values, $name) {
        }
 }
 
-?>
+function enc_image_src($str) {
+       list($src, $width, $height, $a, $b, $c) = explode(' ', $str);
+       return $src;
+}
+
+function enc_image_width($str) {
+       list($src, $width, $height, $a, $b, $c) = explode(' ', $str);
+       return $width;
+}
+
+function enc_image_height($str) {
+       list($src, $width, $height, $a, $b, $c) = explode(' ', $str);
+       return $height;
+}
+
+function enc_thumb_src($str) {
+       list($a, $b, $c, $src, $width, $height) = explode(' ', $str);
+       return $src;
+}
+
+function enc_thumb_width($str) {
+       list($a, $b, $c, $src, $width, $height) = explode(' ', $str);
+       return $width;
+}
+function enc_thumb_height($str) {
+       list($a, $b, $c, $src, $width, $height) = explode(' ', $str);
+       return $height;
+}
index f90fc1f..f931cdd 100644 (file)
@@ -112,24 +112,50 @@ function format_filename($str, $allow_uppercase = false) {
        return ereg_replace('^[.-]', '_', $str);
 }
 
+function format_path($str, $allow_uppercase = false) {
+       if(!$allow_uppercase) {
+               $str = strtolower($str);
+       }
+       $str = ereg_replace('[^a-zA-Z0-9_./-]', '_', $str);
+       return ereg_replace('^[.-]', '_', $str);
+}
+
 function client_path_to_filename($path) {
        $filename = ereg_replace(".*[:/\\]", '', $path);
        return format_filename($filename, true);
 }
 
 
-function format_h_w_image($str) {
+function format_image_w_h($str) {
        $fields = explode(' ', $str);
        if(count($fields) != 3) {
                return '';
        }
 
-       list($width, $height, $filename) = $fields;
+       list($filename, $width, $height) = $fields;
+       $filename = format_path($filename);
+       $width = format_int_0($width);
+       $height = format_int_0($height);
+
+       return "$filename $width $height";
+}
+
+function format_image_w_h_thumb_w_h($str) {
+       $fields = explode(' ', $str);
+       if(count($fields) != 6) {
+               die('count: ' . count($fields));
+               return '';
+       }
+
+       list($filename, $width, $height, $thumb_filename, $thumb_width, $thumb_height) = $fields;
+       $filename = format_path($filename);
        $width = format_int_0($width);
        $height = format_int_0($height);
-       $filename = format_filename($filename);
+       $thumb_filename = format_path($thumb_filename);
+       $thumb_width = format_int_0($thumb_width);
+       $thumb_height = format_int_0($thumb_height);
 
-       return "$width $height $filename";
+       return "$filename $width $height $thumb_filename $thumb_width $thumb_height";
 }
 
 function format_varname($str) {
index b2d3c21..04e786a 100644 (file)
@@ -51,7 +51,8 @@ $GLOBALS['types'] = array(
        'rightyesno' => array('checkbox',    'yesno',      'varchar(3)'),
        'yesno' =>      array('leftcheck',   'yesno',      'varchar(3)'),
        'delete' =>     array('checkbox',    'yesno',      'n/a'),
-       'image' =>      array('image',       'oneline',    'varchar(200)'),
+       'image' =>      array('image',       'oneline',    'varchar(120)'),
+       'thumb' =>      array('image',       'oneline',    'varchar(240)'),
        'submit' =>     array('submit',      'oneline',    'n/a')
 );
 
@@ -244,6 +245,9 @@ function make_html($whole_file = true) {
 
                if($GLOBALS['opt_display'] == 'Yes') {
                        switch($input) {
+                               case 'image':
+                                       $tem->show('display_image');
+                               break;
                                case 'checkbox':
                                case 'leftcheck':
                                        $tem->show('display_yesno');
@@ -270,10 +274,15 @@ function make_html($whole_file = true) {
                        if(show_in_listing($type, $input, $format, $sql)) {
                                if($format == 'bool' || $format == 'yesno') {
                                        $tem->set('listing_enc', 'yesno');
+                                       $tem->show('listing_value_enc');
                                } elseif($input == 'date') {
                                        $tem->set('listing_enc', 'mmddyyyy');
+                                       $tem->show('listing_value_enc');
+                               } elseif($type == 'thumb') {
+                                       $tem->show('listing_value_thumb');
                                } else {
                                        $tem->set('listing_enc', 'html');
+                                       $tem->show('listing_value_enc');
                                }
                                $tem->show('listing_head_col');
                                $tem->show('listing_row_col');
@@ -333,11 +342,13 @@ function show_in_listing($type, $input, $format, $sql) {
                case 'textarea':
                case 'html':
                        return false;
-               default:
-                       return true;
        }
-}
+       if($type == 'image') {
+               return false;
+       }
 
+       return true;
+}
 
 function make_php() {
        $tem = new tem();
@@ -364,8 +375,13 @@ function make_php() {
                                $php_fields .= '$' . $name;
                        }
                        if($input == 'image') {
+                               if($type == 'thumb') {
+                                       $tem->show('thumb_settings');
+                                       $tem->show('thumb_upload_params');
+                                       $tem->show('thumb_w_h');
+                               }
+                               $tem->show('image_settings');
                                $tem->show('image_upload');
-                               $tem->show('image_db');
                                if(!$image_included_yet) {
                                        $tem->show('image_include');
                                        $tem->show('upload_max');
@@ -438,7 +454,6 @@ function view_php() {
        echo make_php();
 }
 
-
 function make_email() {
        $tem = new tem();
        $tem->load('code/wfpl/metaform/template.email.txt');
@@ -474,7 +489,6 @@ function view_email() {
        echo make_email();
 }
 
-
 function preview() {
        tem_load('code/wfpl/metaform/preview.html');
        tem_set('file_name', $GLOBALS['file_name']);
@@ -523,5 +537,3 @@ function download_tar() {
 
 metaform();
 exit();
-
-?>
index 68dac08..0c5c774 100644 (file)
@@ -49,7 +49,9 @@
 <!--~~display_body start~~-->
   <h2>~singular.cap~ details</h2>
     <table border="0" cellpadding="3" cellspacing="0" summary="">
-<!--~display_row start~--><!--~display_yesno start~-->
+<!--~display_row start~--><!--~display_image start~-->
+      <tr><td class="caption">~caption.html~:</td><td><img src="~~~name~.image_src~~" width="~~~name~.image_width~~" height="~~~name~.image_height~~" alt="" /></td></tr>
+<!--~end~--><!--~display_yesno start~-->
       <tr><td class="caption">~caption.html~:</td><td>~~~name~.yesno~~</td></tr>
 <!--~end~--><!--~display_date start~-->
       <tr><td class="caption">~caption.html~:</td><td>~~~name~.mmddyyyy~~</td></tr>
@@ -87,7 +89,7 @@
   <table cellspacing="0" cellpadding="4" border="1" summary="">
     <!--~listing_head_col start~--><th>~caption~</th><!--~end~--><th>&nbsp;</th><!--~~listing_row start~~-->
     <tr><!--~listing_row_col start~-->
-      <td class="listing"><a href="~file_name~?~file_name~_<!--~opt_display_a_else start~-->edit_<!--~end~-->id=~~id~~">~~~name~.~listing_enc~~~</a></td><!--~end~-->
+      <td class="listing"><a href="~file_name~?~file_name~_<!--~opt_display_a_else start~-->edit_<!--~end~-->id=~~id~~"><!--~listing_value_enc start~-->~~~name~.~listing_enc~~~<!--~end~--><!--~listing_value_thumb start~--><img src="~~~name~.thumb_src~~" width="~~~name~.thumb_width~~" height="~~~name~.thumb_height~~" alt="" /><!--~end~--></a></td><!--~end~-->
       <td><a href="~file_name~?~file_name~_delete_id=~~id~~" onclick="return confirm('Permanently delete?')">[delete this ~singular~]</a></td>
     </tr><!--~~end~~-->
 
index bdd7da1..1822ff3 100644 (file)
@@ -25,7 +25,13 @@ define('~file_name.upper~_DB_FIELDS', '~db_fields~');
 # Set this to the path to your uploads directory. It can be relative to the
 # location of this script. IT MUST END WITH A SLASH
 $GLOBALS['upload_directory'] = 'uploads/';
-<!--~end~--><!--~opt_http_pass_1 start~-->
+<!--~end~--><!--~image_settings start~-->
+$GLOBALS['~name~_max_width'] = '400';
+$GLOBALS['~name~_max_height'] = '400';<!--~thumb_settings start~-->
+$GLOBALS['~name~_thumb_max_width'] = '70';
+$GLOBALS['~name~_thumb_max_height'] = '70';
+$GLOBALS['~name~_file_name'] = uniqid() . getmypid() . '.jpg'; # comment this out to use uploader's filename
+<!--~end~--><!--~end~--><!--~opt_http_pass_1 start~-->
 # Define the username and password required to view this form:
 define('AUTH_REALM', '~file_name~ administration area');
 define('AUTH_USER', 'fixme');
@@ -42,12 +48,12 @@ require_once('code/wfpl/upload.php');<!--~end~-->
 function ~file_name~_get_fields() {<!--~formats start~-->
        $~name~ = format_~format~($_REQUEST['~name~']<!--~pulldown_format_extra start~-->, '~name~'<!--~end~-->);<!--~end~--><!--~image_upload start~-->
        if($_FILES['~name~'] && $_FILES['~name~']['error'] == 0) {
-               $~name~ = substr(save_uploaded_image('~name~', $GLOBALS['upload_directory']), strlen($GLOBALS['upload_directory']));
+               $~name~ = convert_uploaded_image('~name~', $GLOBALS['upload_directory'] . $GLOBALS['~name~_file_name'], $GLOBALS['~name~_max_width'], $GLOBALS['~name~_max_height']<!--~thumb_upload_params start~-->, $GLOBALS['~name~_thumb_max_width'], $GLOBALS['~name~_thumb_max_height']<!--~end~-->);
        } else {
                if($_REQUEST['delete_~name~'] == 'Yes') {
                        $~name~ = '';
                } else {
-                       $~name~ = format_filename($_REQUEST['old_~name~']);
+                       $~name~ = format_image_w_h<!--~thumb_w_h start~-->_thumb_w_h<!--~end~-->($_REQUEST['old_~name~']);
                }
        }<!--~end~-->
 
index 1bca71a..f52f0cf 100644 (file)
@@ -116,12 +116,18 @@ function generate_filename($path, $mime = 'text/plain') {
        # remove dots from the beginning (no invisible files)
        $filename = ereg_replace('^\.*', '', $filename);
 
+       if(strlen($filename > 80)) {
+               $filename = substr($filename, -80);
+       }
+
        # fix extension
        $last_dot = strrpos($filename, '.');
        if($last_dot === false) {
                #no extension
                if(isset($GLOBALS['mime_to_ext'][$mime])) {
                        $filename .= '.' . $GLOBALS['mime_to_ext'][$mime];
+               } else {
+                       $filename .= '.bin';
                }
        } else {
                $basename = substr($filename, 0, $last_dot);
@@ -138,15 +144,27 @@ function generate_filename($path, $mime = 'text/plain') {
 
 # Move uploaded file, and return the new filename.
 #
-# Pass in the index into the $_FILES array (the name of the html input tag) and
-# the path to the folder you'd like it saved to. If path ends with a slash this
-# function will generate a filename based on the client's name, otherwise it'll
-# name the file that.
+# $key: Pass in the index into the $_FILES array (the name of the html input tag) and
+# the path to the folder you'd like it saved to.
 #
-# example: save_uploaded_file('pdf', 'uploaded_pdfs/');
-# example: save_uploaded_file('resume', "/www/example.com/remumes/$user_id.txt");
+# $path: If path ends with a slash this function will generate a filename based
+# on the client's name. If it ends with a period, the dot will be removed and
+# the client's name appended. Otherwise $path will be used as the filename
+# exactly as is, even if extensions differ between the client's name and $path.
+#
+# where user uploads "c:\foo\Bar baz.PDF" at <input name="in" type="file" />
+#    save_uploaded_file('in', 'uploaded_pdfs/'); yeilds:
+#       "uploaded_pdfs/bar_baz.pdf"
+#    save_uploaded_file('in', 'uploaded_pdfs/prefix.'); yeilds:
+#       "uploaded_pdfs/prefixbar_baz.pdf"
+#    save_uploaded_file('in', 'uploaded_pdfs/qux.pdf'); yeilds:
+#       "uploaded_pdfs/qux.pdf"
 function save_uploaded_file($key, $path) {
-       if(substr($path, -1) == '/') {
+       $end = substr($path, -1);
+       if($end == '.' || $end == '/') {
+               if($end == '.') {
+                       $path = substr($path, 0, -1);
+               }
                $filename = $path . generate_filename($_FILES[$key]['name'], $_FILES[$key]['type']);
        } else {
                $filename = $path;
@@ -206,14 +224,8 @@ function gif_to_png($filename, $new_filename = 'just change extension') {
                $new_filename .= '.png';
        }
 
-       $convert = path_to('convert');
-
-       $command = "$convert " . escapeshellarg($filename) . ' ' . escapeshellarg($new_filename);
+       imagemagick_convert($filename, $new_filename, "$convert -colorspace RGB", 'GIF to PNG conversion');
 
-       exec($command, $dummy, $ret);
-       if($ret != 0) {
-               die("image conversion failed. convert did exit($ret)");
-       }
        unlink($filename);
        return $new_filename;
 }
@@ -235,26 +247,56 @@ function make_thumbnail($filename, $max_width = '70', $max_height = '70') {
        $thumb .= '_thumb';
        $thumb .= substr($filename, $last_dot);
 
-       $convert = path_to('convert');
+       $max_width = format_int_70($max_width);
+       $height_width = format_int_70($height_width);
 
-       # can't be too careful
-       $max_width = ereg_replace('[^0-9]', '', $max_width);
-       if($max_width == '') {
-               $max_width = '70';
-       }
-       $max_height = ereg_replace('[^0-9]', '', $max_height);
-       if($max_height == '') {
-               $max_height = '70';
-       }
+       imagemagick_convert($filename, $thumb, "-geometry ${max_width}x$max_height", 'Thumbnail creation');
        
-       $command = "$convert -geometry ${max_width}x$max_height " . escapeshellarg($filename) . ' ' . escapeshellarg($thumb);
+       return $thumb;
+}
 
+function exec_or_die($command, $doing_what) {
        exec($command, $dummy, $ret);
        if($ret != 0) {
-               die("Thumbnail creation failed. Convert called exit($ret)");
+               $base = basename(ereg_replace(' .*', '', $command));
+               die("$doing_what failed. $base called exit($ret)");
        }
+}
 
-       return $thumb;
+# exec convert from imagemagick.
+function imagemagick_convert($in_filename, $out_filename, $args, $doing_what = "Image conversion") {
+       $in = escapeshellarg($in_filename);
+       $out = escapeshellarg($out_filename);
+       $command = path_to('convert') . " $in $args $out";
+
+       exec_or_die($command, $doing_what);
+}
+
+# exec mogrify from imagemagick.
+function imagemagick_mogrify($in_filename, $args, $doing_what = "Image conversion") {
+       $command = path_to('mogrify') . " $args " . escapeshellarg($in_filename);
+
+       exec_or_die($command, $doing_what);
+}
+
+function format_int_70($str) {
+       $str = ereg_replace('[^0-9]', '', $str);
+       if($str == '') {
+               $str = '70';
+       }
+       return $str;
+}
+       
+
+# Resize image.
+#
+# The image will retain aspect ratio, and be either $max_width wide or
+# $max_height tall (or, if the aspect is just right, both)
+function resize_image($filename, $max_width = '70', $max_height = '70') {
+       $max_width = format_int_70($max_width);
+       $height_width = format_int_70($height_width);
+       
+       imagimagick_mogrify($filename, "-geometry ${max_width}x$max_height");
 }
 
 # Argument: path to image file
@@ -273,19 +315,95 @@ function image_dimensions($image) {
        }
 }
 
-# like save_uploaded_file() (above) except it converts gifs to pngs.
+# return an array of the width and height of the image passed.
+# calls die() if this can't be done for any reason.
+function image_w_h_or_die($filename) {
+       $wxh = image_dimensions($filename);
+       if($wxh == false) {
+               die("couldn't git image dimensions of $filename");
+       }
+       $wh = explode('x', $wxh);
+       if(count($wh) != 2) {
+               die("image $filename seems to have " . count($wh) . ' dimensions');
+       }
+       return $wh;
+}
+
+
+# Like save_uploaded_file() (above) except that it converts all images to PNG
+# or JPEG, converts to RGB colorspace, and optionally scales and/or creates a
+# thumbnail. And, if $path ends with a period, the correct extension will be
+# appended.
 #
-# FIXME: if a filename is passed in the end of path, we should check if the file type matches, and if not run convert.
-function save_uploaded_image($key, $path) {
-       if(substr($path, -1) == '/') {
-               $filename = save_uploaded_file($key, $path);
-               if(substr($filename, -4) == '.gif') {
-                       $filename = gif_to_png($filename);
-               }
-               return $filename;
+# You are encouraged to use convert_uploaded_image() instead of this function,
+# because it has a more useful return value.
+#
+# If the image_width and image_height parameters are above zero, then the image
+# will be scaled (see below).
+#
+# If the thumb_width and thumb_height parameters are above zero, then a 2nd
+# image will be created and scaled (see below) with the same name, except
+# having "_thumb" added before the extension.
+#
+# Scaling: images are scaled (maintaining the aspect ratio) so they are as big
+# as possible without either dimension being larger than what you specify.
+#
+# This function just returns the name of the main image. To get the dimensions
+# and names, call convert_uploaded_image().
+function save_uploaded_image($key, $path, $image_width = 0, $image_height = 0, $thumbnail_width = 0, $thumbnail_height = 0) {
+     $image_w_h_thumb_w_h = convert_uploaded_image($key, $path, $image_width, $image_height, $thumbnail_width, $thumbnail_height);
+     return ereg_replace(' .*', '', $image_w_h_thumb_w_h);
+}
+
+function ext_to_web_image_ext($in) {
+       if($in == 'png' || $in == 'gif') {
+               return 'png';
        } else {
-               return save_uploaded_file($key, $path);
+               return 'jpg';
        }
 }
 
-?>
+# this function is just like save_uploaded_image() above except that the return
+# value is a string like "filename width height" or (if you specified both
+# thumbnail dimensions) "image_filename image_width image_height thumb_filename
+# thumb_width thumb_height"
+#
+#
+# examples:
+#    convert_uploaded_image('image', 'uploads/', 500, 500);
+#          might return: "uploads/foo.jpg 500 400"
+#    convert_uploaded_image('image', 'uploads/', 500, 500, 70, 70);
+#          might return: "uploads/foo.jpg 500 400 uploads/foo_thumb.jpg 70 56"
+function convert_uploaded_image($key, $path, $image_width = 0, $image_height = 0, $thumb_width = 0, $thumb_height = 0) {
+       $ret = '';
+       $tmp_filename = save_uploaded_file($key, $path . '__.');
+       $ext_rpos = strrpos($tmp_filename, '.');
+       if($ext_rpos === false) {
+               die('save_uploaded_file() gave us a filename with no extension.');
+       }
+       $tmp_base = substr($tmp_filename, 0, $ext_rpos);
+       $tmp_ext = substr($tmp_filename, $ext_rpos + 1);
+       if(substr($path, -1) == '/') {
+               $filename = $path . substr($tmp_base, strlen($path) + 2);
+               $filename .= '.' . ext_to_web_image_ext($tmp_ext);
+       } elseif(substr($path, -1) == '.') {
+               $filename = $path . ext_to_web_image_ext($tmp_ext);
+       } else {
+               $filename = $path;
+       }
+
+       $convert_params = '-colorspace RGB';
+       if($image_width > 0 && $image_height > 0) {
+               $convert_params .= " -geometry ${image_width}x$image_height";
+       }
+       imagemagick_convert($tmp_filename, $filename, $convert_params);
+       unlink($tmp_filename);
+       list($w, $h) = image_w_h_or_die($filename);
+       $ret = "$filename $w $h";
+       if($thumb_width > 0 && $thumb_height > 0) {
+               $thumb_name = make_thumbnail($filename, $thumb_width, $thumb_height);
+               list($w, $h) = image_w_h_or_die($thumb_name);
+               $ret .= " $thumb_name $w $h";
+       }
+       return $ret;
+}