X-Git-Url: https://jasonwoof.com/gitweb/?p=wfpl.git;a=blobdiff_plain;f=upload.php;h=b21af6ffc1d0c9daee027cb1e9c92e9d8f292c6f;hp=05e18664279cab3efdf9c38321ee7004c5b35de1;hb=HEAD;hpb=e73b1d9a880634fd76ae416a41b34013fc64db00 diff --git a/upload.php b/upload.php index 05e1866..b21af6f 100644 --- a/upload.php +++ b/upload.php @@ -1,22 +1,9 @@ -# -# -# +# +# +# # # # ####### @@ -93,11 +80,44 @@ function upload_max_filesize() { } } +# return the extension this path should have WITHOUT the period +function path_or_mime_to_ext($path, $mime = 'text/plain', $default = 'txt') { + $last_dot = strrpos($path, '.'); + if($last_dot === false || $last_dot === 0 || $last_dot === (strlen($path) - 1)) { + # no extension + if(isset($GLOBALS['mime_to_ext'][$mime])) { + return $GLOBALS['mime_to_ext'][$mime]; + } else { + return $default; + } + } else { + $ext = strtolower(substr($path, $last_dot + 1)); + if(isset($GLOBALS['ext_to_ext'][$ext])) { + return $GLOBALS['ext_to_ext'][$ext]; + } + return $ext; + } +} + +# Add or fix extension on path +# This just does string manipulation (ie doesn't move/open/etc any files.) +# Mime type used to generate extension ONLY IF it doesn't have one already. +function path_fix_ext($path, $mime = 'text/plain', $default_ext = '.txt') { + $last_dot = strrpos($path, '.'); + if($last_dot === false || $last_dot === 0) { # no extension + $path .= '.' . path_or_mime_to_ext($path, $mime, $default_ext); + } else { + $basename = substr($path, 0, $last_dot + 1); # keep dot + $path = $basename . path_or_mime_to_ext($path, $mime, $default_ext); + } + + return $path; +} # pass in the client's path that came from an html tag # # mime time used to generate extension ONLY IF it doesn't have one already. -function generate_filename($path, $mime = 'text/plain') { +function generate_filename($path, $mime = 'text/plain', $default_ext = '.txt') { # lower case $filename = strtolower($path); @@ -114,26 +134,23 @@ function generate_filename($path, $mime = 'text/plain') { } # replace symbols with underscores - $filename = ereg_replace('[^a-z0-9_.]', '_', $filename); + $filename = preg_replace('|[^a-z0-9_.]|', '_', $filename); + + # limit length + if(strlen($filename > 80)) { + $filename = substr($filename, -80); + } # remove dots from the beginning (no invisible files) - $filename = ereg_replace('^\.*', '', $filename); + $filename = preg_replace('|^\.*|', '', $filename); - # 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 { - $basename = substr($filename, 0, $last_dot); - $ext = substr($filename, $last_dot + 1); - if(isset($GLOBALS['ext_to_ext'][$ext])) { - $ext .= $GLOBALS['ext_to_ext'][$ext]; - } - $filename = $basename . '.' . $ext; + # make sure there's something before the extension + if ($filename == '') { + return '_'; } + + $filename = path_fix_ext($filename, $mime, $default_ext); + return $filename; } @@ -141,15 +158,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 +# 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; @@ -162,22 +191,38 @@ function save_uploaded_file($key, $path) { return $filename; } -function path_to_convert() { - if(!isset($GLOBALS['path_to_convert'])) { - $GLOBALS['path_to_convert'] = _path_to_convert(); +# this function exists to deal with cases where binaries are installed in very +# standard places (like /usr/bin or /usr/local bin) and PHP's PATH environment +# variable is not set appropriately. +function path_to($prog, $or_die = true) { + $prog = preg_replace('|[^a-z0-9_.-]|i', '', $prog); + $prog = preg_replace('|^[-.]*|', '', $prog); + if($prog == '') { + die('Invalid argument to path_to()'); } - return $GLOBALS['path_to_convert']; -} + if(!isset($GLOBALS["path_to_$prog"])) { + $ret = _path_to($prog, $or_die); + if($ret == false) { + return false; + } + $GLOBALS["path_to_$prog"] = $ret; + } -function _path_to_convert() { + return $GLOBALS["path_to_$prog"]; +} + +function _path_to($prog, $or_die) { # relies on PHP's short-circuit mechanism - if(file_exists($convert = '/usr/local/bin/convert') || - file_exists($convert = '/usr/bin/convert') || - ($convert = `which convert` != '' && file_exists($convert))) { - return $convert; + if(file_exists($path = "/usr/local/bin/$prog") || + file_exists($path = "/usr/bin/$prog") || + ($path = `which $prog` != '' && file_exists($path))) { + return $path; } else { - die("can't find imagemagick's 'convert' program"); + if($or_die) { + die("Failed to locate '$prog' executable."); + } + return false; } } @@ -193,14 +238,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.'[0]', $new_filename, "-colorspace sRGB", 'GIF to PNG conversion'); - exec($command, $dummy, $ret); - if($ret != 0) { - die("image conversion failed. convert did exit($ret)"); - } unlink($filename); return $new_filename; } @@ -213,46 +252,172 @@ function gif_to_png($filename, $new_filename = 'just change extension') { # Thumbnail will retain aspect ratio, and be either $max_width wide or # $max_height tall (or, if the aspect is just right, both) function make_thumbnail($filename, $max_width = '70', $max_height = '70') { - $thumb = ereg_replace('[.]([a-z]+)$', "_thumb.\\1", $filename); - if($thumb == $filename) { + $last_dot = strrpos($filename, '.'); + if($last_dot === false) { die("couldn't make thumbnail because filename has no extension."); } - $convert = path_to_convert(); + $thumb = substr($filename, 0, $last_dot); + $thumb .= '_thumb'; + $thumb .= substr($filename, $last_dot); - # 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'; - } + $max_width = format_int_70($max_width); + $height_width = format_int_70($height_width); + + 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 creatin failed. convert did exit($ret)"); + $base = basename(preg_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 = preg_replace('|[^0-9]|', '', $str); + if($str == '') { + $str = '70'; + } + return $str; } + -# like save_uploaded_file() (above) except it converts gifs to pngs. +# Resize image. # -# 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; +# 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 +# +# Return: string in the format WIDTHxHEIGHT, or boolean false +# +# Example: image_dimensions('uploads/foo.png'); ==> "124x58" +function image_dimensions($image) { + $identify = path_to('identify'); + $command = "$identify -format '%wx%h' " . escapeshellarg($image); + $dimensions = rtrim(`$command`); + if($dimensions == '') { + return false; } else { - return save_uploaded_file($key, $path); + return $dimensions; + } +} + +# 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 sRGB colorspace, and optionally scales and/or creates a +# thumbnail. And, if $path ends with a period, the correct extension will be +# appended. +# +# 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 preg_replace('| .*|', '', $image_w_h_thumb_w_h); +} + +function ext_to_web_image_ext($in) { + if($in == 'png' || $in == 'gif') { + return 'png'; + } else { + 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 sRGB -auto-orient'; + if($image_width > 0 && $image_height > 0) { + $convert_params .= " -geometry ${image_width}x$image_height"; + } + imagemagick_convert($tmp_filename.'[0]', $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; +}