diff --git imagefield_crop.module imagefield_crop.module index 0dc6a84..270115c 100644 --- imagefield_crop.module +++ imagefield_crop.module @@ -19,9 +19,9 @@ function imagefield_crop_field_widget_info() { 'progress_indicator' => 'throbber', 'preview_image_style' => 'thumbnail', 'collapsible' => 2, - 'resolution' => '200x150', - 'enforce_ratio' => TRUE, - 'enforce_minimum' => TRUE, + 'resolution' => '0x0', + 'enforce_ratio' => FALSE, + 'enforce_minimum' => FALSE, 'croparea' => '500x500', ), 'behaviors' => array( @@ -143,7 +143,7 @@ function _imagefield_crop_widget_enforce_minimum_validate($element, &$form_state $rw = ($settings['resolution']['x']) ? $settings['resolution']['x'] : 0; $rh = ($settings['resolution']['y']) ? $settings['resolution']['y'] : 0; - if ($settings['enforce_minimum'] && + if ($settings['enforce_minimum'] && (!is_numeric($rw) || intval($rw) != $rw || $rw <= 0 || !is_numeric($rh) || intval($rh) != $rh || $rh <= 0)) { form_error($element, t('Target resolution must be defined as WIDTH_HEIGHT if minimum is to be enforced.')); @@ -224,7 +224,11 @@ function imagefield_crop_widget_process($element, &$form_state, $form) { 'id' => $element['#id'] . '-cropbox'))), ); $element['cropinfo'] = _imagefield_add_cropinfo_fields($element['#file']->fid); - list($res_w, $res_h) = explode('x', $widget_settings['resolution']); + if (!empty($widget_settings['resolution'])) { + list($res_w, $res_h) = explode('x', $widget_settings['resolution']); + } else { + $res_w = $res_h = 0; + } list($crop_w, $crop_h) = explode('x', $widget_settings['croparea']); $settings = array( $element['#id'] => array( @@ -246,10 +250,10 @@ function imagefield_crop_widget_process($element, &$form_state, $form) { 'scope' => 'header', ); } - + // prepend submit handler to remove button array_unshift($element['remove_button']['#submit'], 'imagefield_crop_widget_delete'); - + return $element; } @@ -257,8 +261,8 @@ function _imagefield_add_cropinfo_fields($fid = NULL) { $defaults = array( 'x' => 0, 'y' => 0, - 'width' => 50, - 'height' => 50, + 'width' => 2048, + 'height' => 2048, 'changed' => 0, ); if ($fid) { @@ -279,7 +283,6 @@ function _imagefield_add_cropinfo_fields($fid = NULL) { return $element; } - function imagefield_crop_widget_preview_process($element, &$form_state, $form) { //dpm(__FUNCTION__); $file = $element['#file']; @@ -292,6 +295,8 @@ function imagefield_crop_widget_preview_process($element, &$form_state, $form) { $instance = field_widget_instance($parent, $form_state); if ($instance['widget']['settings']['resolution']) { list($width, $height) = explode('x', $instance['widget']['settings']['resolution']); + } else { + $width = $height = 0; } $image_info = image_get_info(drupal_realpath($file->uri)); @@ -334,13 +339,16 @@ function imagefield_crop_widget_value(&$element, &$input, $form_state) { $instance = field_widget_instance($element, $form_state); if ($instance['widget']['settings']['resolution']) { list($scale['width'], $scale['height']) = explode('x', $instance['widget']['settings']['resolution']); + } else { + $scale = null; } $src = file_load($input['fid']); $file_to_crop = _imagefield_crop_file_to_crop($src->fid); // Copy the original aside, for future cropping + if ($file_to_crop->fid == $src->fid && - $orig_uri = file_unmanaged_copy($src->uri, $src->uri)) { + $orig_uri = file_unmanaged_copy_ex($src->uri)) { $orig = clone $src; $orig->fid = 0; $orig->uri = $orig_uri; @@ -354,8 +362,8 @@ function imagefield_crop_widget_value(&$element, &$input, $form_state) { // // Save crop data to the database // $src->imagefield_crop = array('crop' => $crop); // file_save($src); - - if (_imagefield_crop_resize(drupal_realpath($file_to_crop->uri), $crop, $scale, drupal_realpath($src->uri))) { + + if (_imagefield_crop_resize($file_to_crop->uri, $crop, $scale, $src->uri)) { // insert crop info for this image in imagefield_crop_info variable $crop_info = variable_get('imagefield_crop_info', array()); unset($crop['changed']); @@ -364,7 +372,6 @@ function imagefield_crop_widget_value(&$element, &$input, $form_state) { // Remove cached versions of the cropped image. image_path_flush($src->uri); } - } } @@ -428,6 +435,111 @@ function _imagefield_crop_entity_presave($entity, $fields) { } } +/** + * Copies a file to a new location without invoking the file API. + * + * This is a powerful function that in many ways performs like an advanced + * version of copy(). + * - Checks if $source and $destination are valid and readable/writable. + * - If file already exists in $destination either the call will error out, + * replace the file or rename the file based on the $replace parameter. + * - If the $source and $destination are equal, the behavior depends on the + * $replace parameter. FILE_EXISTS_REPLACE will error out. FILE_EXISTS_RENAME + * will rename the file until the $destination is unique. + * - Provides a fallback using realpaths if the move fails using stream + * wrappers. This can occur because PHP's copy() function does not properly + * support streams if safe_mode or open_basedir are enabled. See + * https://bugs.php.net/bug.php?id=60456 + * + * @param $source + * A string specifying the filepath or URI of the source file. + * @param $destination + * A URI containing the destination that $source should be copied to. The + * URI may be a bare filepath (without a scheme). If this value is omitted, + * Drupal's default files scheme will be used, usually "public://". + * @param $replace + * Replace behavior when the destination file already exists: + * - FILE_EXISTS_REPLACE - Replace the existing file. + * - FILE_EXISTS_RENAME - Append _{incrementing number} until the filename is + * unique. + * - FILE_EXISTS_ERROR - Do nothing and return FALSE. + * + * @return + * The path to the new file, or FALSE in the event of an error. + * + * @see file_copy() + */ +function file_unmanaged_copy_ex($source, $destination = NULL, $replace = FILE_EXISTS_RENAME) { + $original_source = $source; + + // Assert that the source file actually exists. + if (!file_exists($source)) { + // @todo Replace drupal_set_message() calls with exceptions instead. + drupal_set_message(t('The specified file %file could not be copied, because no file by that name exists. Please check that you supplied the correct filename.', array('%file' => $original_source)), 'error'); + if (($realpath = drupal_realpath($original_source)) !== FALSE) { + watchdog('file', 'File %file (%realpath) could not be copied because it does not exist.', array('%file' => $original_source, '%realpath' => $realpath)); + } + else { + watchdog('file', 'File %file could not be copied because it does not exist.', array('%file' => $original_source)); + } + return FALSE; + } + + // Build a destination URI if necessary. + if (!isset($destination)) { + $destination = file_build_uri(drupal_basename($source)); + } + + // Prepare the destination directory. + if (file_prepare_directory($destination)) { + // The destination is already a directory, so append the source basename. + $destination = file_stream_wrapper_uri_normalize($destination . '/' . drupal_basename($source)); + } + else { + // Perhaps $destination is a dir/file? + $dirname = drupal_dirname($destination); + if (!file_prepare_directory($dirname)) { + // The destination is not valid. + watchdog('file', 'File %file could not be copied, because the destination directory %destination is not configured correctly.', array('%file' => $original_source, '%destination' => $dirname)); + drupal_set_message(t('The specified file %file could not be copied, because the destination directory is not properly configured. This may be caused by a problem with file or directory permissions. More information is available in the system log.', array('%file' => $original_source)), 'error'); + return FALSE; + } + } + + // Determine whether we can perform this operation based on overwrite rules. + $destination = file_destination($destination, $replace); + if ($destination === FALSE) { + drupal_set_message(t('The file %file could not be copied because a file by that name already exists in the destination directory.', array('%file' => $original_source)), 'error'); + watchdog('file', 'File %file could not be copied because a file by that name already exists in the destination directory (%directory)', array('%file' => $original_source, '%directory' => $destination)); + return FALSE; + } + + // Assert that the source and destination filenames are not the same. + $real_source = drupal_realpath($source); + $real_destination = drupal_realpath($destination); + if ($source == $destination || ($real_source !== FALSE) && ($real_source == $real_destination)) { + drupal_set_message(t('The specified file %file was not copied because it would overwrite itself.', array('%file' => $source)), 'error'); + watchdog('file', 'File %file could not be copied because it would overwrite itself.', array('%file' => $source)); + return FALSE; + } + // Make sure the .htaccess files are present. + file_ensure_htaccess(); + // Perform the copy operation. + if (!@copy($source, $destination)) { + // If the copy failed and realpaths exist, retry the operation using them + // instead. + if ($real_source === FALSE || $real_destination === FALSE || !@copy($real_source, $real_destination)) { + watchdog('file', 'The specified file %file could not be copied to %destination.', array('%file' => $source, '%destination' => $destination), WATCHDOG_ERROR); + return FALSE; + } + } + + // Set the permissions on the new file. + drupal_chmod($destination); + + return $destination; +} + /*********************/ /* Theming functions */ /*********************/ @@ -486,6 +598,7 @@ function theme_imagefield_crop_preview($variables) { */ function _imagefield_crop_resize($src, $crop = NULL, $scale = NULL, $dst = NULL) { //dpm(__FUNCTION__); + $image = image_load($src); if ($image) { $result = TRUE;