. # This file contains functions to accept files being uplodad with the control. # # ######## # # HTML # # ######## # # First, your
tag must contain this attribute: # enctype="multipart/form-data" # # Second, you should indicate to the browser the maximum file size (in bytes) # allowed for uploads with a hidden input field named MAX_FILE_SIZE. You can # use the function upload_max_filesize() to get the maximum allowed size that # PHP will accept. # # Example: # # # # # #
# # ####### # # PHP # # ####### # # In the php code you can use either save_uploaded_file('photo', # 'upload/dir/'); or save_uploaded_image('photo', 'upload/dir/'); The only # difference being that save_uploaded_image() will convert gifs to PNGs. # # Both functions will generate a reasonable filename based on the filename # passed from the browser (and on the mime-type if there's no extension) unless # you specify a filename. See the comments above the function definitions below # for more details. # # In a future version of save_uploaded_image(), when you specify a filename, it # will check the image type of the uploaded image, and if it's different than # the type you specified, it will convert the image for you. $GLOBALS['mime_to_ext'] = array( 'text/plain' => 'txt', 'text/html' => 'html', 'image/jpeg' => 'jpg', 'image/jpe' => 'jpg', 'image/jpg' => 'jpg', 'image/gif' => 'gif', 'image/png' => 'png', 'application/pdf' => 'pdf' ); $GLOBALS['ext_to_ext'] = array( 'text' => 'txt', 'jpe' => 'jpg', 'jpeg' => 'jpg', 'htm' => 'html' ); # return the upload_max_filesize in bytes function upload_max_filesize() { $max = ini_get('upload_max_filesize'); $postfix = strtolower(substr($max, -1)); if($postfix == 'g') { return substr($max, 0, -1) * 1073741824; } elseif($postfix == 'm') { return substr($max, 0, -1) * 1048576; } elseif ($postfix == 'k') { return substr($max, 0, -1) * 1024; } else { return $max; } } # 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') { # lower case $filename = strtolower($path); # remove directories (unix, windows and mac paths) $last = strrpos($filename, '/'); if($last === false) { $last = strrpos($filename, '\\'); } if($last === false) { $last = strrpos($filename, ':'); } if($last) { $filename = substr($filename, $last + 1); } # replace symbols with underscores $filename = preg_replace('|[^a-z0-9_.]|', '_', $filename); # remove dots from the beginning (no invisible files) $filename = preg_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); $ext = substr($filename, $last_dot + 1); if(isset($GLOBALS['ext_to_ext'][$ext])) { $ext .= $GLOBALS['ext_to_ext'][$ext]; } $filename = $basename . '.' . $ext; } return $filename; } # Move uploaded file, and return the new filename. # # $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. # # $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) { $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; } if(!move_uploaded_file($_FILES[$key]['tmp_name'], $filename)) { return false; } return $filename; } # 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()'); } if(!isset($GLOBALS["path_to_$prog"])) { $ret = _path_to($prog, $or_die); if($ret == false) { return false; } $GLOBALS["path_to_$prog"] = $ret; } return $GLOBALS["path_to_$prog"]; } function _path_to($prog, $or_die) { # relies on PHP's short-circuit mechanism if(file_exists($path = "/usr/local/bin/$prog") || file_exists($path = "/usr/bin/$prog") || ($path = `which $prog` != '' && file_exists($path))) { return $path; } else { if($or_die) { die("Failed to locate '$prog' executable."); } return false; } } # returns new filename with .png extension function gif_to_png($filename, $new_filename = 'just change extension') { if($new_filename == 'just change extension') { $new_filename = $filename; $last_dot = strrpos($new_filename, '.'); if($last_dot !== false) { $new_filename = substr($new_filename, 0, $last_dot); } $new_filename .= '.png'; } imagemagick_convert($filename, $new_filename, "-colorspace sRGB", 'GIF to PNG conversion'); unlink($filename); return $new_filename; } # make a thumbnail image. # # Thumbnail will have the same filename, except "_thumb" will be added right # before the dot preceding the extension. so foo.png yields foo_thumb.png # # 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') { $last_dot = strrpos($filename, '.'); if($last_dot === false) { die("couldn't make thumbnail because filename has no extension."); } $thumb = substr($filename, 0, $last_dot); $thumb .= '_thumb'; $thumb .= substr($filename, $last_dot); $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'); return $thumb; } function exec_or_die($command, $doing_what) { exec($command, $dummy, $ret); if($ret != 0) { $base = basename(preg_replace('| .*|', '', $command)); die("$doing_what failed. $base called exit($ret)"); } } # 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; } # 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 # # 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 $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, $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; }