| 1 |
<?php
|
| 2 |
// $Id: imagecache.module,v 1.111 2009/05/03 18:51:00 drewish Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Dynamic image resizer and image cacher.
|
| 7 |
*
|
| 8 |
* ImageCache allows you to setup presets for image processing.
|
| 9 |
* If an ImageCache derivative doesn't exist the web server's
|
| 10 |
* rewrite rules will pass the request to Drupal which in turn
|
| 11 |
* hands it off to imagecache to dynamically generate the file.
|
| 12 |
*
|
| 13 |
* To view a derivative image you request a special url containing
|
| 14 |
* 'imagecache/<presetname>/path/to/file.ext.
|
| 15 |
*
|
| 16 |
* Presets can be managed at http://example.com/admin/build/imagecache.
|
| 17 |
*
|
| 18 |
* To view a derivative image you request a special url containing
|
| 19 |
* 'imagecache/<presetname>/path/to/file.ext.
|
| 20 |
*
|
| 21 |
* If you had a preset names 'thumbnail' and you wanted to see the
|
| 22 |
* thumbnail version of http://example.com/files/path/to/myimage.jpg you
|
| 23 |
* would use http://example.com/files/imagecache/thumbnail/path/to/myimage.jpg
|
| 24 |
*
|
| 25 |
* ImageCache provides formatters for CCK Imagefields and is leveraged by several
|
| 26 |
* other modules. ImageCache also relies heavily on ImageAPI for it's image processing.
|
| 27 |
* If there are errors with actual image processing look to ImageAPI first.
|
| 28 |
*
|
| 29 |
* @todo: add watermarking capabilities.
|
| 30 |
*
|
| 31 |
*/
|
| 32 |
|
| 33 |
/**
|
| 34 |
* Imagecache preset storage constant for user-defined presets in the DB.
|
| 35 |
*/
|
| 36 |
define('IMAGECACHE_STORAGE_NORMAL', 0);
|
| 37 |
|
| 38 |
/**
|
| 39 |
* Imagecache preset storage constant for module-defined presets in code.
|
| 40 |
*/
|
| 41 |
define('IMAGECACHE_STORAGE_DEFAULT', 1);
|
| 42 |
|
| 43 |
/**
|
| 44 |
* Imagecache preset storage constant for user-defined presets that override
|
| 45 |
* module-defined presets.
|
| 46 |
*/
|
| 47 |
define('IMAGECACHE_STORAGE_OVERRIDE', 2);
|
| 48 |
|
| 49 |
/*********************************************************************************************
|
| 50 |
* Drupal Hooks
|
| 51 |
*********************************************************************************************/
|
| 52 |
|
| 53 |
/**
|
| 54 |
* Implementation of hook_perm().
|
| 55 |
*/
|
| 56 |
function imagecache_perm() {
|
| 57 |
$perms = array('administer imagecache', 'flush imagecache');
|
| 58 |
foreach (imagecache_presets() as $preset) {
|
| 59 |
$perms[] = 'view imagecache '. $preset['presetname'];
|
| 60 |
}
|
| 61 |
return $perms;
|
| 62 |
}
|
| 63 |
|
| 64 |
/**
|
| 65 |
* Implementation of hook_menu().
|
| 66 |
*/
|
| 67 |
function imagecache_menu() {
|
| 68 |
$items = array();
|
| 69 |
|
| 70 |
// standard imagecache callback.
|
| 71 |
$items[file_directory_path() .'/imagecache'] = array(
|
| 72 |
'page callback' => 'imagecache_cache',
|
| 73 |
'access callback' => TRUE,
|
| 74 |
'type' => MENU_CALLBACK
|
| 75 |
);
|
| 76 |
// private downloads imagecache callback
|
| 77 |
$items['system/files/imagecache'] = array(
|
| 78 |
'page callback' => 'imagecache_cache_private',
|
| 79 |
'access callback' => TRUE,
|
| 80 |
'type' => MENU_CALLBACK
|
| 81 |
);
|
| 82 |
|
| 83 |
return $items;
|
| 84 |
}
|
| 85 |
|
| 86 |
/**
|
| 87 |
* Clear imagecache presets cache on admin/build/modules form.
|
| 88 |
*/
|
| 89 |
function imagecache_form_system_modules_alter(&$form, $form_state) {
|
| 90 |
imagecache_presets(TRUE);
|
| 91 |
}
|
| 92 |
|
| 93 |
/**
|
| 94 |
* Implementation of hook_theme().
|
| 95 |
*/
|
| 96 |
function imagecache_theme() {
|
| 97 |
$theme = array(
|
| 98 |
'imagecache' => array(
|
| 99 |
'arguments' => array(
|
| 100 |
'namespace' => NULL,
|
| 101 |
'path' => NULL,
|
| 102 |
'alt' => NULL,
|
| 103 |
'title' => NULL,
|
| 104 |
)),
|
| 105 |
'imagecache_imagelink' => array(
|
| 106 |
'arguments' => array(
|
| 107 |
'namespace' => NULL,
|
| 108 |
'path' => NULL,
|
| 109 |
'alt' => NULL,
|
| 110 |
'title' => NULL,
|
| 111 |
'attributes' => array(),
|
| 112 |
)),
|
| 113 |
'imagecache_resize' => array(
|
| 114 |
'file' => 'imagecache_actions.inc',
|
| 115 |
'arguments' => array('element' => NULL),
|
| 116 |
),
|
| 117 |
'imagecache_scale' => array(
|
| 118 |
'file' => 'imagecache_actions.inc',
|
| 119 |
'arguments' => array('element' => NULL),
|
| 120 |
),
|
| 121 |
'imagecache_scale_and_crop' => array(
|
| 122 |
'file' => 'imagecache_actions.inc',
|
| 123 |
'arguments' => array('element' => NULL),
|
| 124 |
),
|
| 125 |
'imagecache_deprecated_scale' => array(
|
| 126 |
'file' => 'imagecache_actions.inc',
|
| 127 |
'arguments' => array('element' => NULL),
|
| 128 |
),
|
| 129 |
'imagecache_crop' => array(
|
| 130 |
'file' => 'imagecache_actions.inc',
|
| 131 |
'arguments' => array('element' => NULL),
|
| 132 |
),
|
| 133 |
'imagecache_desaturate' => array(
|
| 134 |
'file' => 'imagecache_actions.inc',
|
| 135 |
'arguments' => array('element' => NULL),
|
| 136 |
),
|
| 137 |
'imagecache_rotate' => array(
|
| 138 |
'file' => 'imagecache_actions.inc',
|
| 139 |
'arguments' => array('element' => NULL),
|
| 140 |
),
|
| 141 |
'imagecache_sharpen' => array(
|
| 142 |
'file' => 'imagecache_actions.inc',
|
| 143 |
'arguments' => array('element' => NULL),
|
| 144 |
),
|
| 145 |
);
|
| 146 |
|
| 147 |
foreach (imagecache_presets() as $preset) {
|
| 148 |
$theme['imagecache_formatter_'. $preset['presetname'] .'_default'] = array(
|
| 149 |
'arguments' => array('element' => NULL),
|
| 150 |
'function' => 'theme_imagecache_formatter_default',
|
| 151 |
);
|
| 152 |
$theme['imagecache_formatter_'. $preset['presetname'] .'_linked'] = array(
|
| 153 |
'arguments' => array('element' => NULL),
|
| 154 |
'function' => 'theme_imagecache_formatter_linked',
|
| 155 |
);
|
| 156 |
$theme['imagecache_formatter_'. $preset['presetname'] .'_imagelink'] = array(
|
| 157 |
'arguments' => array('element' => NULL),
|
| 158 |
'function' => 'theme_imagecache_formatter_imagelink',
|
| 159 |
);
|
| 160 |
$theme['imagecache_formatter_'. $preset['presetname'] .'_path'] = array(
|
| 161 |
'arguments' => array('element' => NULL),
|
| 162 |
'function' => 'theme_imagecache_formatter_path',
|
| 163 |
);
|
| 164 |
$theme['imagecache_formatter_'. $preset['presetname'] .'_url'] = array(
|
| 165 |
'arguments' => array('element' => NULL),
|
| 166 |
'function' => 'theme_imagecache_formatter_url',
|
| 167 |
);
|
| 168 |
}
|
| 169 |
|
| 170 |
return $theme;
|
| 171 |
|
| 172 |
}
|
| 173 |
|
| 174 |
/**
|
| 175 |
* Implementation of hook_imagecache_actions.
|
| 176 |
*
|
| 177 |
* @return array
|
| 178 |
* An array of information on the actions implemented by a module. The array
|
| 179 |
* contains a sub-array for each action node type, with the machine-readable
|
| 180 |
* action name as the key. Each sub-array has up to 3 attributes. Possible
|
| 181 |
* attributes:
|
| 182 |
*
|
| 183 |
* "name": the human-readable name of the action. Required.
|
| 184 |
* "description": a brief description of the action. Required.
|
| 185 |
* "file": the name of the include file the action can be found
|
| 186 |
* in relative to the implementing module's path.
|
| 187 |
*/
|
| 188 |
function imagecache_imagecache_actions() {
|
| 189 |
$actions = array(
|
| 190 |
'imagecache_resize' => array(
|
| 191 |
'name' => 'Resize',
|
| 192 |
'description' => 'Resize an image to an exact set of dimensions, ignoring aspect ratio.',
|
| 193 |
'file' => 'imagecache_actions.inc',
|
| 194 |
),
|
| 195 |
'imagecache_scale' => array(
|
| 196 |
'name' => 'Scale',
|
| 197 |
'description' => 'Resize an image maintaining the original aspect-ratio (only one value necessary).',
|
| 198 |
'file' => 'imagecache_actions.inc',
|
| 199 |
),
|
| 200 |
'imagecache_deprecated_scale' => array(
|
| 201 |
'name' => 'Deprecated Scale',
|
| 202 |
'description' => 'Precursor to Scale and Crop. Has inside and outside dimension support. This action will be removed in ImageCache 2.1).',
|
| 203 |
'file' => 'imagecache_actions.inc',
|
| 204 |
),
|
| 205 |
'imagecache_scale_and_crop' => array(
|
| 206 |
'name' => 'Scale And Crop',
|
| 207 |
'description' => 'Resize an image while maintaining aspect ratio, then crop it to the specified dimensions.',
|
| 208 |
'file' => 'imagecache_actions.inc',
|
| 209 |
),
|
| 210 |
'imagecache_crop' => array(
|
| 211 |
'name' => 'Crop',
|
| 212 |
'description' => 'Crop an image to the rectangle specified by the given offsets and dimensions.',
|
| 213 |
'file' => 'imagecache_actions.inc',
|
| 214 |
),
|
| 215 |
'imagecache_desaturate' => array(
|
| 216 |
'name' => 'Desaturate',
|
| 217 |
'description' => 'Convert an image to grey scale.',
|
| 218 |
'file' => 'imagecache_actions.inc',
|
| 219 |
),
|
| 220 |
'imagecache_rotate' => array(
|
| 221 |
'name' => 'Rotate',
|
| 222 |
'description' => 'Rotate an image.',
|
| 223 |
'file' => 'imagecache_actions.inc',
|
| 224 |
),
|
| 225 |
'imagecache_sharpen' => array(
|
| 226 |
'name' => 'Sharpen',
|
| 227 |
'description' => 'Sharpen an image using unsharp masking.',
|
| 228 |
'file' => 'imagecache_actions.inc',
|
| 229 |
),
|
| 230 |
);
|
| 231 |
|
| 232 |
return $actions;
|
| 233 |
}
|
| 234 |
|
| 235 |
/**
|
| 236 |
* Pull in actions exposed by other modules using hook_imagecache_actions().
|
| 237 |
*
|
| 238 |
* @param $reset
|
| 239 |
* Boolean flag indicating whether the cached data should be
|
| 240 |
* wiped and recalculated.
|
| 241 |
*
|
| 242 |
* @return
|
| 243 |
* An array of actions to be used when transforming images.
|
| 244 |
*/
|
| 245 |
function imagecache_action_definitions($reset = FALSE) {
|
| 246 |
static $actions;
|
| 247 |
if (!isset($actions) || $reset) {
|
| 248 |
if (!$reset && ($cache = cache_get('imagecache_actions')) && !empty($cache->data)) {
|
| 249 |
$actions = $cache->data;
|
| 250 |
}
|
| 251 |
else {
|
| 252 |
foreach (module_implements('imagecache_actions') as $module) {
|
| 253 |
foreach (module_invoke($module, 'imagecache_actions') as $key => $action) {
|
| 254 |
$action['module'] = $module;
|
| 255 |
if (!empty($action['file'])) {
|
| 256 |
$action['file'] = drupal_get_path('module', $action['module']) .'/'. $action['file'];
|
| 257 |
}
|
| 258 |
$actions[$key] = $action;
|
| 259 |
};
|
| 260 |
}
|
| 261 |
uasort($actions, '_imagecache_definitions_sort');
|
| 262 |
cache_set('imagecache_actions', $actions);
|
| 263 |
}
|
| 264 |
}
|
| 265 |
return $actions;
|
| 266 |
}
|
| 267 |
|
| 268 |
function _imagecache_definitions_sort($a, $b) {
|
| 269 |
$a = $a['name'];
|
| 270 |
$b = $b['name'];
|
| 271 |
if ($a == $b) {
|
| 272 |
return 0;
|
| 273 |
}
|
| 274 |
return ($a < $b) ? -1 : 1;
|
| 275 |
}
|
| 276 |
|
| 277 |
function imagecache_action_definition($action) {
|
| 278 |
static $definition_cache;
|
| 279 |
if (!isset($definition_cache[$action])) {
|
| 280 |
$definitions = imagecache_action_definitions();
|
| 281 |
$definition = (isset($definitions[$action])) ? $definitions[$action] : array();
|
| 282 |
|
| 283 |
if (isset($definition['file'])) {
|
| 284 |
require_once($definition['file']);
|
| 285 |
}
|
| 286 |
$definition_cache[$action] = $definition;
|
| 287 |
}
|
| 288 |
return $definition_cache[$action];
|
| 289 |
}
|
| 290 |
|
| 291 |
/**
|
| 292 |
* Return a URL that points to the location of a derivative of the
|
| 293 |
* original image transformed with the given preset.
|
| 294 |
*
|
| 295 |
* Special care is taken to make this work with the possible combinations of
|
| 296 |
* Clean URLs and public/private downloads. For example, when Clean URLs are not
|
| 297 |
* available an URL with query should be returned, like
|
| 298 |
* http://example.com/?q=files/imagecache/foo.jpg, so that imagecache is able
|
| 299 |
* intercept the request for this file.
|
| 300 |
*
|
| 301 |
* This code is very similar to the Drupal core function file_create_url(), but
|
| 302 |
* handles the case of Clean URLs and public downloads differently however.
|
| 303 |
*
|
| 304 |
* @param $presetname
|
| 305 |
* @param $filepath
|
| 306 |
* String specifying the path to the image file.
|
| 307 |
* @param $bypass_browser_cache
|
| 308 |
* A Boolean indicating that the URL for the image should be distinct so that
|
| 309 |
* the visitors browser will not be able to use a previously cached version.
|
| 310 |
* This is
|
| 311 |
*/
|
| 312 |
function imagecache_create_url($presetname, $filepath, $bypass_browser_cache = FALSE) {
|
| 313 |
$path = _imagecache_strip_file_directory($filepath);
|
| 314 |
if (module_exists('transliteration')) {
|
| 315 |
$path = transliteration_get($path);
|
| 316 |
}
|
| 317 |
|
| 318 |
$args = array('absolute' => TRUE, 'query' => $bypass_browser_cache ? time() : $bypass_browser_cache);
|
| 319 |
switch (variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC)) {
|
| 320 |
case FILE_DOWNLOADS_PUBLIC:
|
| 321 |
return url($GLOBALS['base_url'] . '/' . file_directory_path() .'/imagecache/'. $presetname .'/'. $path, $args);
|
| 322 |
case FILE_DOWNLOADS_PRIVATE:
|
| 323 |
return url('system/files/imagecache/'. $presetname .'/'. $path, $args);
|
| 324 |
}
|
| 325 |
}
|
| 326 |
|
| 327 |
/**
|
| 328 |
* Return a file system location that points to the location of a derivative
|
| 329 |
* of the original image at @p $path, transformed with the given @p $preset.
|
| 330 |
* Keep in mind that the image might not yet exist and won't be created.
|
| 331 |
*/
|
| 332 |
function imagecache_create_path($presetname, $path) {
|
| 333 |
$path = _imagecache_strip_file_directory($path);
|
| 334 |
return file_create_path() .'/imagecache/'. $presetname .'/'. $path;
|
| 335 |
}
|
| 336 |
|
| 337 |
/**
|
| 338 |
* Remove a possible leading file directory path from the given path.
|
| 339 |
*/
|
| 340 |
function _imagecache_strip_file_directory($path) {
|
| 341 |
$dirpath = file_directory_path();
|
| 342 |
$dirlen = strlen($dirpath);
|
| 343 |
if (substr($path, 0, $dirlen + 1) == $dirpath .'/') {
|
| 344 |
$path = substr($path, $dirlen + 1);
|
| 345 |
}
|
| 346 |
return $path;
|
| 347 |
}
|
| 348 |
|
| 349 |
|
| 350 |
/**
|
| 351 |
* callback for handling public files imagecache requests.
|
| 352 |
*/
|
| 353 |
function imagecache_cache() {
|
| 354 |
$args = func_get_args();
|
| 355 |
$preset = check_plain(array_shift($args));
|
| 356 |
$path = implode('/', $args);
|
| 357 |
_imagecache_cache($preset, $path);
|
| 358 |
}
|
| 359 |
|
| 360 |
/**
|
| 361 |
* callback for handling private files imagecache requests
|
| 362 |
*/
|
| 363 |
function imagecache_cache_private() {
|
| 364 |
$args = func_get_args();
|
| 365 |
$preset = check_plain(array_shift($args));
|
| 366 |
$source = implode('/', $args);
|
| 367 |
|
| 368 |
if (user_access('view imagecache '. $preset)) {
|
| 369 |
_imagecache_cache($preset, $source);
|
| 370 |
}
|
| 371 |
else {
|
| 372 |
// if there is a 403 image, display it.
|
| 373 |
$accesspath = file_create_path('imagecache/'. $preset .'.403.png');
|
| 374 |
if (is_file($accesspath)) {
|
| 375 |
imagecache_transfer($accesspath);
|
| 376 |
exit;
|
| 377 |
}
|
| 378 |
header('HTTP/1.0 403 Forbidden');
|
| 379 |
exit;
|
| 380 |
}
|
| 381 |
}
|
| 382 |
|
| 383 |
/**
|
| 384 |
* handle request validation and responses to imagecache requests.
|
| 385 |
*/
|
| 386 |
function _imagecache_cache($presetname, $path) {
|
| 387 |
if (!$preset = imagecache_preset_by_name($presetname)) {
|
| 388 |
// Send a 404 if we don't know of a preset.
|
| 389 |
header("HTTP/1.0 404 Not Found");
|
| 390 |
exit;
|
| 391 |
}
|
| 392 |
|
| 393 |
// umm yeah deliver it early if it is there. especially useful
|
| 394 |
// to prevent lock files from being created when delivering private files.
|
| 395 |
$dst = imagecache_create_path($preset['presetname'], $path);
|
| 396 |
if (is_file($dst)) {
|
| 397 |
imagecache_transfer($dst);
|
| 398 |
}
|
| 399 |
|
| 400 |
// preserve path for watchdog.
|
| 401 |
$src = $path;
|
| 402 |
|
| 403 |
// Check if the path to the file exists.
|
| 404 |
if (!is_file($src) && !is_file($src = file_create_path($src))) {
|
| 405 |
watchdog('imagecache', '404: Unable to find %image ', array('%image' => $src), WATCHDOG_ERROR);
|
| 406 |
header("HTTP/1.0 404 Not Found");
|
| 407 |
exit;
|
| 408 |
};
|
| 409 |
|
| 410 |
// Bail if the requested file isn't an image you can't request .php files
|
| 411 |
// etc...
|
| 412 |
if (!getimagesize($src)) {
|
| 413 |
watchdog('imagecache', '403: File is not an image %image ', array('%image' => $src), WATCHDOG_ERROR);
|
| 414 |
header('HTTP/1.0 403 Forbidden');
|
| 415 |
exit;
|
| 416 |
}
|
| 417 |
|
| 418 |
$lockfile = file_directory_temp() .'/'. $preset['presetname'] . basename($src);
|
| 419 |
if (file_exists($lockfile)) {
|
| 420 |
watchdog('imagecache', 'ImageCache already generating: %dst, Lock file: %tmp.', array('%dst' => $dst, '%tmp' => $lockfile), WATCHDOG_NOTICE);
|
| 421 |
// 307 Temporary Redirect, to myself. Lets hope the image is done next time around.
|
| 422 |
header('Location: '. request_uri(), TRUE, 307);
|
| 423 |
exit;
|
| 424 |
}
|
| 425 |
touch($lockfile);
|
| 426 |
// register the shtdown function to clean up lock files. by the time shutdown
|
| 427 |
// functions are being called the cwd has changed from document root, to
|
| 428 |
// server root so absolute paths must be used for files in shutdown functions.
|
| 429 |
register_shutdown_function('file_delete', realpath($lockfile));
|
| 430 |
|
| 431 |
// check if deriv exists... (file was created between apaches request handler and reaching this code)
|
| 432 |
// otherwise try to create the derivative.
|
| 433 |
if (file_exists($dst) || imagecache_build_derivative($preset['actions'], $src, $dst)) {
|
| 434 |
imagecache_transfer($dst);
|
| 435 |
}
|
| 436 |
// Generate an error if image could not generate.
|
| 437 |
watchdog('imagecache', 'Failed generating an image from %image using imagecache preset %preset.', array('%image' => $path, '%preset' => $preset['presetname']), WATCHDOG_ERROR);
|
| 438 |
header("HTTP/1.0 500 Internal Server Error");
|
| 439 |
exit;
|
| 440 |
}
|
| 441 |
|
| 442 |
/**
|
| 443 |
* Apply an action to an image.
|
| 444 |
*
|
| 445 |
* @param $action
|
| 446 |
* Action array
|
| 447 |
* @param $image
|
| 448 |
* Image object
|
| 449 |
* @return
|
| 450 |
* Boolean, TRUE indicating success and FALSE failure.
|
| 451 |
*/
|
| 452 |
function _imagecache_apply_action($action, $image) {
|
| 453 |
$actions = imagecache_action_definitions();
|
| 454 |
|
| 455 |
if ($definition = imagecache_action_definition($action['action'])) {
|
| 456 |
$function = $action['action'] .'_image';
|
| 457 |
if (function_exists($function)) {
|
| 458 |
return $function($image, $action['data']);
|
| 459 |
}
|
| 460 |
}
|
| 461 |
// skip undefined actions.. module probably got uninstalled or disabled.
|
| 462 |
watchdog('imagecache', 'non-existant action %action', array('%action' => $action['action']), WATCHDOG_NOTICE);
|
| 463 |
return TRUE;
|
| 464 |
}
|
| 465 |
|
| 466 |
/**
|
| 467 |
* Helper function to transfer files from imagecache.
|
| 468 |
*
|
| 469 |
* Determines MIME type and sets a last modified header.
|
| 470 |
*
|
| 471 |
* @param $path
|
| 472 |
* String containing the path to file to be transferred.
|
| 473 |
* @return
|
| 474 |
* This function does not return. It calls exit().
|
| 475 |
*/
|
| 476 |
|
| 477 |
function imagecache_transfer($path) {
|
| 478 |
$size = getimagesize($path);
|
| 479 |
$headers = array('Content-Type: '. mime_header_encode($size['mime']));
|
| 480 |
|
| 481 |
if ($fileinfo = stat($path)) {
|
| 482 |
$headers[] = 'Content-Length: '. $fileinfo[7];
|
| 483 |
_imagecache_cache_set_cache_headers($fileinfo, $headers);
|
| 484 |
}
|
| 485 |
file_transfer($path, $headers);
|
| 486 |
exit;
|
| 487 |
}
|
| 488 |
|
| 489 |
/**
|
| 490 |
* Set file headers that handle "If-Modified-Since" correctly for the
|
| 491 |
* given fileinfo.
|
| 492 |
*
|
| 493 |
* Note that this function may return or may call exit().
|
| 494 |
*
|
| 495 |
* Most code has been taken from drupal_page_cache_header().
|
| 496 |
*
|
| 497 |
* @param $fileinfo
|
| 498 |
* Array returned by stat().
|
| 499 |
* @param
|
| 500 |
* Array of existing headers.
|
| 501 |
* @return
|
| 502 |
* Nothing but beware that this function may not return.
|
| 503 |
*/
|
| 504 |
function _imagecache_cache_set_cache_headers($fileinfo, &$headers) {
|
| 505 |
// Set default values:
|
| 506 |
$last_modified = gmdate('D, d M Y H:i:s', $fileinfo[9]) .' GMT';
|
| 507 |
$etag = '"'. md5($last_modified) .'"';
|
| 508 |
|
| 509 |
// See if the client has provided the required HTTP headers:
|
| 510 |
$if_modified_since = isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])
|
| 511 |
? stripslashes($_SERVER['HTTP_IF_MODIFIED_SINCE'])
|
| 512 |
: FALSE;
|
| 513 |
$if_none_match = isset($_SERVER['HTTP_IF_NONE_MATCH'])
|
| 514 |
? stripslashes($_SERVER['HTTP_IF_NONE_MATCH'])
|
| 515 |
: FALSE;
|
| 516 |
|
| 517 |
if ($if_modified_since && $if_none_match
|
| 518 |
&& $if_none_match == $etag // etag must match
|
| 519 |
&& $if_modified_since == $last_modified) { // if-modified-since must match
|
| 520 |
header('HTTP/1.1 304 Not Modified');
|
| 521 |
// All 304 responses must send an etag if the 200 response
|
| 522 |
// for the same object contained an etag
|
| 523 |
header('Etag: '. $etag);
|
| 524 |
// We must also set Last-Modified again, so that we overwrite Drupal's
|
| 525 |
// default Last-Modified header with the right one
|
| 526 |
header('Last-Modified: '. $last_modified);
|
| 527 |
exit;
|
| 528 |
}
|
| 529 |
|
| 530 |
// Send appropriate response:
|
| 531 |
$headers[] = 'Last-Modified: '. $last_modified;
|
| 532 |
$headers[] = 'ETag: '. $etag;
|
| 533 |
}
|
| 534 |
|
| 535 |
/**
|
| 536 |
* Create a new image based on an image preset.
|
| 537 |
*
|
| 538 |
* @param $preset
|
| 539 |
* An image preset array.
|
| 540 |
* @param $source
|
| 541 |
* Path of the source file.
|
| 542 |
* @param $destination
|
| 543 |
* Path of the destination file.
|
| 544 |
* @return
|
| 545 |
* TRUE if an image derivative is generated, FALSE if no image
|
| 546 |
* derivative is generated. NULL if the derivative is being generated.
|
| 547 |
*/
|
| 548 |
function imagecache_build_derivative($actions, $src, $dst) {
|
| 549 |
// get the folder for the final location of this preset...
|
| 550 |
$dir = dirname($dst);
|
| 551 |
|
| 552 |
// Build the destination folder tree if it doesn't already exists.
|
| 553 |
if (!file_check_directory($dir, FILE_CREATE_DIRECTORY) && !mkdir($dir, 0775, TRUE)) {
|
| 554 |
watchdog('imagecache', 'Failed to create imagecache directory: %dir', array('%dir' => $dir), WATCHDOG_ERROR);
|
| 555 |
return FALSE;
|
| 556 |
}
|
| 557 |
|
| 558 |
// Simply copy the file if there are no actions.
|
| 559 |
if (empty($actions)) {
|
| 560 |
return file_copy($src, $dst, FILE_EXISTS_REPLACE);
|
| 561 |
}
|
| 562 |
|
| 563 |
if (!$image = imageapi_image_open($src)) {
|
| 564 |
return FALSE;
|
| 565 |
}
|
| 566 |
|
| 567 |
if (file_exists($dst)) {
|
| 568 |
watchdog('imagecache', 'Cached image file %dst already exists but is being regenerated. There may be an issue with your rewrite configuration.', array('%dst' => $dst), WATCHDOG_WARNING);
|
| 569 |
}
|
| 570 |
|
| 571 |
foreach ($actions as $action) {
|
| 572 |
if (!empty($action['data'])) {
|
| 573 |
// Make sure the width and height are computed first so they can be used
|
| 574 |
// in relative x/yoffsets like 'center' or 'bottom'.
|
| 575 |
if (isset($action['data']['width'])) {
|
| 576 |
$action['data']['width'] = _imagecache_percent_filter($action['data']['width'], $image->info['width']);
|
| 577 |
}
|
| 578 |
if (isset($action['data']['height'])) {
|
| 579 |
$action['data']['height'] = _imagecache_percent_filter($action['data']['height'], $image->info['height']);
|
| 580 |
}
|
| 581 |
if (isset($action['data']['xoffset'])) {
|
| 582 |
$action['data']['xoffset'] = _imagecache_keyword_filter($action['data']['xoffset'], $image->info['width'], $action['data']['width']);
|
| 583 |
}
|
| 584 |
if (isset($action['data']['yoffset'])) {
|
| 585 |
$action['data']['yoffset'] = _imagecache_keyword_filter($action['data']['yoffset'], $image->info['height'], $action['data']['height']);
|
| 586 |
}
|
| 587 |
}
|
| 588 |
if (!_imagecache_apply_action($action, $image)) {
|
| 589 |
watchdog('imagecache', 'action(id:%id): %action failed for %src', array('%id' => $action['actionid'], '%action' => $action['action'], '%src' => $src), WATCHDOG_ERROR);
|
| 590 |
return FALSE;
|
| 591 |
}
|
| 592 |
}
|
| 593 |
|
| 594 |
if (!imageapi_image_close($image, $dst)) {
|
| 595 |
watchdog('imagecache', 'There was an error saving the new image file %dst.', array('%dst' => $dst), WATCHDOG_ERROR);
|
| 596 |
return FALSE;
|
| 597 |
}
|
| 598 |
|
| 599 |
return TRUE;
|
| 600 |
}
|
| 601 |
|
| 602 |
/**
|
| 603 |
* Implementation of hook_user().
|
| 604 |
*/
|
| 605 |
function imagecache_user($op, &$edit, &$account, $category = NULL) {
|
| 606 |
// Flush cached old user picture.
|
| 607 |
if ($op == 'update' && !empty($account->picture)) {
|
| 608 |
imagecache_image_flush($account->picture);
|
| 609 |
}
|
| 610 |
}
|
| 611 |
|
| 612 |
/**
|
| 613 |
* Implementation of filefield.module's hook_file_delete().
|
| 614 |
*
|
| 615 |
* Remove derivative images after the originals are deleted by filefield.
|
| 616 |
*/
|
| 617 |
function imagecache_file_delete($file) {
|
| 618 |
imagecache_image_flush($file->filepath);
|
| 619 |
}
|
| 620 |
|
| 621 |
/**
|
| 622 |
* Implementation of hook_field_formatter_info().
|
| 623 |
*
|
| 624 |
* imagecache formatters are named as $presetname_$style
|
| 625 |
* $style is used to determine how the preset should be rendered.
|
| 626 |
* If you are implementing custom imagecache formatters please treat _ as
|
| 627 |
* reserved.
|
| 628 |
*
|
| 629 |
* @todo: move the linking functionality up to imagefield and clean up the default image
|
| 630 |
* integration.
|
| 631 |
*/
|
| 632 |
function imagecache_field_formatter_info() {
|
| 633 |
$formatters = array();
|
| 634 |
foreach (imagecache_presets() as $preset) {
|
| 635 |
$formatters[$preset['presetname'] .'_default'] = array(
|
| 636 |
'label' => t('@preset image', array('@preset' => $preset['presetname'])),
|
| 637 |
'field types' => array('image', 'filefield'),
|
| 638 |
);
|
| 639 |
$formatters[$preset['presetname'] .'_linked'] = array(
|
| 640 |
'label' => t('@preset image linked to node', array('@preset' => $preset['presetname'])),
|
| 641 |
'field types' => array('image', 'filefield'),
|
| 642 |
);
|
| 643 |
$formatters[$preset['presetname'] .'_imagelink'] = array(
|
| 644 |
'label' => t('@preset image linked to image', array('@preset' => $preset['presetname'])),
|
| 645 |
'field types' => array('image', 'filefield'),
|
| 646 |
);
|
| 647 |
$formatters[$preset['presetname'] .'_path'] = array(
|
| 648 |
'label' => t('@preset file path', array('@preset' => $preset['presetname'])),
|
| 649 |
'field types' => array('image', 'filefield'),
|
| 650 |
);
|
| 651 |
$formatters[$preset['presetname'] .'_url'] = array(
|
| 652 |
'label' => t('@preset URL', array('@preset' => $preset['presetname'])),
|
| 653 |
'field types' => array('image', 'filefield'),
|
| 654 |
);
|
| 655 |
}
|
| 656 |
return $formatters;
|
| 657 |
}
|
| 658 |
|
| 659 |
function theme_imagecache_formatter_default($element) {
|
| 660 |
// Inside a view $element may contain NULL data. In that case, just return.
|
| 661 |
if (empty($element['#item']['fid'])) {
|
| 662 |
return '';
|
| 663 |
}
|
| 664 |
|
| 665 |
// Extract the preset name from the formatter name.
|
| 666 |
$presetname = substr($element['#formatter'], 0, strrpos($element['#formatter'], '_'));
|
| 667 |
$style = 'linked';
|
| 668 |
$style = 'default';
|
| 669 |
|
| 670 |
$item = $element['#item'];
|
| 671 |
$item['data']['alt'] = isset($item['data']['alt']) ? $item['data']['alt'] : '';
|
| 672 |
$item['data']['title'] = isset($item['data']['title']) ? $item['data']['title'] : NULL;
|
| 673 |
|
| 674 |
$class = "imagecache imagecache-$presetname imagecache-$style imagecache-{$element['#formatter']}";
|
| 675 |
return theme('imagecache', $presetname, $item['filepath'], $item['data']['alt'], $item['data']['title'], array('class' => $class));
|
| 676 |
}
|
| 677 |
|
| 678 |
function theme_imagecache_formatter_linked($element) {
|
| 679 |
// Inside a view $element may contain NULL data. In that case, just return.
|
| 680 |
if (empty($element['#item']['fid'])) {
|
| 681 |
return '';
|
| 682 |
}
|
| 683 |
|
| 684 |
// Extract the preset name from the formatter name.
|
| 685 |
$presetname = substr($element['#formatter'], 0, strrpos($element['#formatter'], '_'));
|
| 686 |
$style = 'linked';
|
| 687 |
|
| 688 |
$item = $element['#item'];
|
| 689 |
$item['data']['alt'] = isset($item['data']['alt']) ? $item['data']['alt'] : '';
|
| 690 |
$item['data']['title'] = isset($item['data']['title']) ? $item['data']['title'] : NULL;
|
| 691 |
|
| 692 |
$imagetag = theme('imagecache', $presetname, $item['filepath'], $item['data']['alt'], $item['data']['title']);
|
| 693 |
$path = empty($item['nid']) ? '' : 'node/'. $item['nid'];
|
| 694 |
$class = "imagecache imagecache-$presetname imagecache-$style imagecache-{$element['#formatter']}";
|
| 695 |
return l($imagetag, $path, array('attributes' => array('class' => $class), 'html' => TRUE));
|
| 696 |
}
|
| 697 |
|
| 698 |
function theme_imagecache_formatter_imagelink($element) {
|
| 699 |
// Inside a view $element may contain NULL data. In that case, just return.
|
| 700 |
if (empty($element['#item']['fid'])) {
|
| 701 |
return '';
|
| 702 |
}
|
| 703 |
|
| 704 |
// Extract the preset name from the formatter name.
|
| 705 |
$presetname = substr($element['#formatter'], 0, strrpos($element['#formatter'], '_'));
|
| 706 |
$style = 'imagelink';
|
| 707 |
|
| 708 |
$item = $element['#item'];
|
| 709 |
$item['data']['alt'] = isset($item['data']['alt']) ? $item['data']['alt'] : '';
|
| 710 |
$item['data']['title'] = isset($item['data']['title']) ? $item['data']['title'] : NULL;
|
| 711 |
|
| 712 |
$imagetag = theme('imagecache', $presetname, $item['filepath'], $item['data']['alt'], $item['data']['title']);
|
| 713 |
$path = file_create_url($item['filepath']);
|
| 714 |
$class = "imagecache imagecache-$presetname imagecache-$style imagecache-{$element['#formatter']}";
|
| 715 |
return l($imagetag, $path, array('attributes' => array('class' => $class), 'html' => TRUE));
|
| 716 |
}
|
| 717 |
|
| 718 |
function theme_imagecache_formatter_path($element) {
|
| 719 |
// Inside a view $element may contain NULL data. In that case, just return.
|
| 720 |
if (empty($element['#item']['fid'])) {
|
| 721 |
return '';
|
| 722 |
}
|
| 723 |
|
| 724 |
// Extract the preset name from the formatter name.
|
| 725 |
$presetname = substr($element['#formatter'], 0, strrpos($element['#formatter'], '_'));
|
| 726 |
|
| 727 |
return imagecache_create_path($presetname, $element['#item']['filepath']);
|
| 728 |
}
|
| 729 |
|
| 730 |
function theme_imagecache_formatter_url($element) {
|
| 731 |
// Inside a view $element may contain NULL data. In that case, just return.
|
| 732 |
if (empty($element['#item']['fid'])) {
|
| 733 |
return '';
|
| 734 |
}
|
| 735 |
|
| 736 |
// Extract the preset name from the formatter name.
|
| 737 |
$presetname = substr($element['#formatter'], 0, strrpos($element['#formatter'], '_'));
|
| 738 |
|
| 739 |
return imagecache_create_url($presetname, $element['#item']['filepath']);
|
| 740 |
}
|
| 741 |
|
| 742 |
/**
|
| 743 |
* Accept a percentage and return it in pixels.
|
| 744 |
*/
|
| 745 |
function _imagecache_percent_filter($value, $current_pixels) {
|
| 746 |
if (strpos($value, '%') !== FALSE) {
|
| 747 |
$value = str_replace('%', '', $value) * 0.01 * $current_pixels;
|
| 748 |
}
|
| 749 |
return $value;
|
| 750 |
}
|
| 751 |
|
| 752 |
/**
|
| 753 |
* Accept a keyword (center, top, left, etc) and return it as an offset in pixels.
|
| 754 |
*/
|
| 755 |
function _imagecache_keyword_filter($value, $current_pixels, $new_pixels) {
|
| 756 |
switch ($value) {
|
| 757 |
case 'top':
|
| 758 |
case 'left':
|
| 759 |
$value = 0;
|
| 760 |
break;
|
| 761 |
case 'bottom':
|
| 762 |
case 'right':
|
| 763 |
$value = $current_pixels - $new_pixels;
|
| 764 |
break;
|
| 765 |
case 'center':
|
| 766 |
$value = $current_pixels/2 - $new_pixels/2;
|
| 767 |
break;
|
| 768 |
}
|
| 769 |
return $value;
|
| 770 |
}
|
| 771 |
|
| 772 |
/**
|
| 773 |
* Recursively delete all files and folders in the specified filepath, then
|
| 774 |
* delete the containing folder.
|
| 775 |
*
|
| 776 |
* Note that this only deletes visible files with write permission.
|
| 777 |
*
|
| 778 |
* @param string $path
|
| 779 |
* A filepath relative to file_directory_path.
|
| 780 |
*/
|
| 781 |
function _imagecache_recursive_delete($path) {
|
| 782 |
if (is_file($path) || is_link($path)) {
|
| 783 |
unlink($path);
|
| 784 |
}
|
| 785 |
elseif (is_dir($path)) {
|
| 786 |
$d = dir($path);
|
| 787 |
while (($entry = $d->read()) !== FALSE) {
|
| 788 |
if ($entry == '.' || $entry == '..') continue;
|
| 789 |
$entry_path = $path .'/'. $entry;
|
| 790 |
_imagecache_recursive_delete($entry_path);
|
| 791 |
}
|
| 792 |
$d->close();
|
| 793 |
rmdir($path);
|
| 794 |
}
|
| 795 |
else {
|
| 796 |
watchdog('imagecache', 'Unknown file type(%path) stat: %stat ',
|
| 797 |
array('%path' => $path, '%stat' => print_r(stat($path),1)), WATCHDOG_ERROR);
|
| 798 |
}
|
| 799 |
|
| 800 |
}
|
| 801 |
|
| 802 |
/**
|
| 803 |
* Create and image tag for an imagecache derivative
|
| 804 |
*
|
| 805 |
* @param $presetname
|
| 806 |
* String with the name of the preset used to generate the derivative image.
|
| 807 |
* @param $path
|
| 808 |
* String path to the original image you wish to create a derivative image
|
| 809 |
* tag for.
|
| 810 |
* @param $alt
|
| 811 |
* Optional string with alternate text for the img element.
|
| 812 |
* @param $title
|
| 813 |
* Optional string with title for the img element.
|
| 814 |
* @param $attributes
|
| 815 |
* Optional drupal_attributes() array. If $attributes is an array then the
|
| 816 |
* default imagecache classes will not be set automatically, you must do this
|
| 817 |
* manually.
|
| 818 |
* @param $getsize
|
| 819 |
* If set to TRUE, the image's dimension are fetched and added as width/height
|
| 820 |
* attributes.
|
| 821 |
* @return
|
| 822 |
* HTML img element string.
|
| 823 |
*/
|
| 824 |
function theme_imagecache($presetname, $path, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE) {
|
| 825 |
// Check is_null() so people can intentionally pass an empty array of
|
| 826 |
// to override the defaults completely.
|
| 827 |
if (is_null($attributes)) {
|
| 828 |
$attributes = array('class' => 'imagecache imagecache-'. $presetname);
|
| 829 |
}
|
| 830 |
if ($getsize && ($image = image_get_info(imagecache_create_path($presetname, $path)))) {
|
| 831 |
$attributes['width'] = $image['width'];
|
| 832 |
$attributes['height'] = $image['height'];
|
| 833 |
}
|
| 834 |
|
| 835 |
$attributes = drupal_attributes($attributes);
|
| 836 |
$imagecache_url = imagecache_create_url($presetname, $path);
|
| 837 |
return '<img src="'. $imagecache_url .'" alt="'. check_plain($alt) .'" title="'. check_plain($title) .'" '. $attributes .' />';
|
| 838 |
}
|
| 839 |
|
| 840 |
/**
|
| 841 |
* Create a link the original image that wraps the derivative image.
|
| 842 |
*
|
| 843 |
* @param $presetname
|
| 844 |
* String with the name of the preset used to generate the derivative image.
|
| 845 |
* @param $path
|
| 846 |
* String path to the original image you wish to create a derivative image
|
| 847 |
* tag for.
|
| 848 |
* @param $alt
|
| 849 |
* Optional string with alternate text for the img element.
|
| 850 |
* @param $title
|
| 851 |
* Optional string with title for the img element.
|
| 852 |
* @param attributes
|
| 853 |
* Optional drupal_attributes() array for the link.
|
| 854 |
* @return
|
| 855 |
* An HTML string.
|
| 856 |
*/
|
| 857 |
function theme_imagecache_imagelink($presetname, $path, $alt = '', $title = '', $attributes = NULL) {
|
| 858 |
$image = theme('imagecache', $presetname, $path, $alt, $title);
|
| 859 |
$original_image_url = file_create_url($path);
|
| 860 |
return l($image, $original_image_url, array('absolute' => FALSE, 'html' => TRUE));
|
| 861 |
}
|
| 862 |
|
| 863 |
/**
|
| 864 |
* ImageCache 2.x API
|
| 865 |
*
|
| 866 |
* The API for imagecache has changed. The 2.x API returns more structured
|
| 867 |
* data, has shorter function names, and implements more aggressive metadata
|
| 868 |
* caching.
|
| 869 |
*
|
| 870 |
*/
|
| 871 |
|
| 872 |
/**
|
| 873 |
* Get an array of all presets and their settings.
|
| 874 |
*
|
| 875 |
* @param reset
|
| 876 |
* if set to TRUE it will clear the preset cache
|
| 877 |
*
|
| 878 |
* @return
|
| 879 |
* array of presets array( $preset_id => array('presetid' => integer, 'presetname' => string))
|
| 880 |
*/
|
| 881 |
function imagecache_presets($reset = FALSE) {
|
| 882 |
static $presets = array();
|
| 883 |
|
| 884 |
// Clear caches if $reset is TRUE;
|
| 885 |
if ($reset) {
|
| 886 |
$presets = array();
|
| 887 |
cache_clear_all('imagecache:presets', 'cache');
|
| 888 |
|
| 889 |
// Clear the content.module cache (refreshes the list of formatters provided by imagefield.module).
|
| 890 |
if (module_exists('content')) {
|
| 891 |
content_clear_type_cache();
|
| 892 |
}
|
| 893 |
}
|
| 894 |
// Return presets if the array is populated.
|
| 895 |
if (!empty($presets)) {
|
| 896 |
return $presets;
|
| 897 |
}
|
| 898 |
|
| 899 |
// Grab from cache or build the array. To ensure that the Drupal 5 upgrade
|
| 900 |
// path works, we also check whether the presets list is an array.
|
| 901 |
if (($cache = cache_get('imagecache:presets', 'cache')) && is_array($cache->data)) {
|
| 902 |
$presets = $cache->data;
|
| 903 |
}
|
| 904 |
else {
|
| 905 |
$normal_presets = array();
|
| 906 |
|
| 907 |
$result = db_query('SELECT * FROM {imagecache_preset} ORDER BY presetname');
|
| 908 |
while ($preset = db_fetch_array($result)) {
|
| 909 |
$presets[$preset['presetid']] = $preset;
|
| 910 |
$presets[$preset['presetid']]['actions'] = imagecache_preset_actions($preset);
|
| 911 |
$presets[$preset['presetid']]['storage'] = IMAGECACHE_STORAGE_NORMAL;
|
| 912 |
|
| 913 |
// Collect normal preset names so we can skip defaults and mark overrides accordingly
|
| 914 |
$normal_presets[$preset['presetname']] = $preset['presetid'];
|
| 915 |
}
|
| 916 |
|
| 917 |
// Collect default presets and allow modules to modify them before they
|
| 918 |
// are cached.
|
| 919 |
$default_presets = module_invoke_all('imagecache_default_presets');
|
| 920 |
drupal_alter('imagecache_default_presets', $default_presets);
|
| 921 |
|
| 922 |
// Add in default presets if they don't conflict with any normal presets.
|
| 923 |
// Mark normal presets that take the same preset namespace as overrides.
|
| 924 |
foreach ($default_presets as $preset) {
|
| 925 |
if (!empty($preset['presetname'])) {
|
| 926 |
if (!isset($normal_presets[$preset['presetname']])) {
|
| 927 |
$preset['storage'] = IMAGECACHE_STORAGE_DEFAULT;
|
| 928 |
// Use a string preset identifier
|
| 929 |
$preset['presetid'] = $preset['presetname'];
|
| 930 |
$presets[$preset['presetname']] = $preset;
|
| 931 |
}
|
| 932 |
else {
|
| 933 |
$presetid = $normal_presets[$preset['presetname']];
|
| 934 |
$presets[$presetid]['storage'] = IMAGECACHE_STORAGE_OVERRIDE;
|
| 935 |
}
|
| 936 |
}
|
| 937 |
}
|
| 938 |
|
| 939 |
cache_set('imagecache:presets', $presets);
|
| 940 |
}
|
| 941 |
return $presets;
|
| 942 |
}
|
| 943 |
|
| 944 |
/**
|
| 945 |
* Load a preset by preset_id.
|
| 946 |
*
|
| 947 |
* @param preset_id
|
| 948 |
* The numeric id of a preset.
|
| 949 |
*
|
| 950 |
* @return
|
| 951 |
* preset array( 'presetname' => string, 'presetid' => integet)
|
| 952 |
* empty array if preset_id is an invalid preset
|
| 953 |
*/
|
| 954 |
function imagecache_preset($preset_id, $reset = FALSE) {
|
| 955 |
$presets = imagecache_presets($reset);
|
| 956 |
return (isset($presets[$preset_id])) ? $presets[$preset_id] : array();
|
| 957 |
}
|
| 958 |
|
| 959 |
/**
|
| 960 |
* Load a preset by name.
|
| 961 |
*
|
| 962 |
* @param preset_name
|
| 963 |
*
|
| 964 |
* @return
|
| 965 |
* preset array( 'presetname' => string, 'presetid' => integer)
|
| 966 |
* empty array if preset_name is an invalid preset
|
| 967 |
*/
|
| 968 |
|
| 969 |
function imagecache_preset_by_name($preset_name) {
|
| 970 |
static $presets_by_name = array();
|
| 971 |
if (!$presets_by_name && $presets = imagecache_presets()) {
|
| 972 |
foreach ($presets as $preset) {
|
| 973 |
$presets_by_name[$preset['presetname']] = $preset;
|
| 974 |
}
|
| 975 |
}
|
| 976 |
return (isset($presets_by_name[$preset_name])) ? $presets_by_name[$preset_name] : array();
|
| 977 |
}
|
| 978 |
|
| 979 |
/**
|
| 980 |
* Save an ImageCache preset.
|
| 981 |
*
|
| 982 |
* @param preset
|
| 983 |
* an imagecache preset array.
|
| 984 |
* @return
|
| 985 |
* a preset array. In the case of a new preset, 'presetid' will be populated.
|
| 986 |
*/
|
| 987 |
function imagecache_preset_save($preset) {
|
| 988 |
// @todo: CRUD level validation?
|
| 989 |
if (isset($preset['presetid']) && is_numeric($preset['presetid'])) {
|
| 990 |
drupal_write_record('imagecache_preset', $preset, 'presetid');
|
| 991 |
}
|
| 992 |
else {
|
| 993 |
drupal_write_record('imagecache_preset', $preset);
|
| 994 |
}
|
| 995 |
|
| 996 |
// Reset presets cache.
|
| 997 |
imagecache_preset_flush($preset);
|
| 998 |
imagecache_presets(TRUE);
|
| 999 |
|
| 1000 |
// Rebuild Theme Registry
|
| 1001 |
drupal_rebuild_theme_registry();
|
| 1002 |
|
| 1003 |
return $preset;
|
| 1004 |
}
|
| 1005 |
|
| 1006 |
function imagecache_preset_delete($preset) {
|
| 1007 |
imagecache_preset_flush($preset['presetid']);
|
| 1008 |
db_query('DELETE FROM {imagecache_action} where presetid = %d', $preset['presetid']);
|
| 1009 |
db_query('DELETE FROM {imagecache_preset} where presetid = %d', $preset['presetid']);
|
| 1010 |
imagecache_presets(TRUE);
|
| 1011 |
return TRUE;
|
| 1012 |
}
|
| 1013 |
|
| 1014 |
function imagecache_preset_actions($preset, $reset = FALSE) {
|
| 1015 |
static $actions_cache = array();
|
| 1016 |
|
| 1017 |
if ($reset || empty($actions_cache[$preset['presetid']])) {
|
| 1018 |
$result = db_query('SELECT * FROM {imagecache_action} where presetid = %d order by weight', $preset['presetid']);
|
| 1019 |
while ($row = db_fetch_array($result)) {
|
| 1020 |
$row['data'] = unserialize($row['data']);
|
| 1021 |
$actions_cache[$preset['presetid']][] = $row;
|
| 1022 |
}
|
| 1023 |
}
|
| 1024 |
|
| 1025 |
return isset($actions_cache[$preset['presetid']]) ? $actions_cache[$preset['presetid']] : array();
|
| 1026 |
}
|
| 1027 |
|
| 1028 |
/**
|
| 1029 |
* Flush cached media for a preset.
|
| 1030 |
* @param id
|
| 1031 |
* A preset id.
|
| 1032 |
*/
|
| 1033 |
function imagecache_preset_flush($preset) {
|
| 1034 |
if (user_access('flush imagecache')) {
|
| 1035 |
$presetdir = realpath(file_directory_path() .'/imagecache/'. $preset['presetname']);
|
| 1036 |
if (is_dir($presetdir)) {
|
| 1037 |
_imagecache_recursive_delete($presetdir);
|
| 1038 |
}
|
| 1039 |
}
|
| 1040 |
}
|
| 1041 |
|
| 1042 |
/**
|
| 1043 |
* Clear cached versions of a specific file in all presets.
|
| 1044 |
* @param $path
|
| 1045 |
* The Drupal file path to the original image.
|
| 1046 |
*/
|
| 1047 |
function imagecache_image_flush($path) {
|
| 1048 |
foreach (imagecache_presets() as $preset) {
|
| 1049 |
file_delete(imagecache_create_path($preset['presetname'], $path));
|
| 1050 |
}
|
| 1051 |
}
|
| 1052 |
|
| 1053 |
function imagecache_action($actionid) {
|
| 1054 |
static $actions;
|
| 1055 |
|
| 1056 |
if (!isset($actions[$actionid])) {
|
| 1057 |
$action = array();
|
| 1058 |
|
| 1059 |
$result = db_query('SELECT * FROM {imagecache_action} WHERE actionid=%d', $actionid);
|
| 1060 |
if ($row = db_fetch_array($result)) {
|
| 1061 |
$action = $row;
|
| 1062 |
$action['data'] = unserialize($action['data']);
|
| 1063 |
|
| 1064 |
$definition = imagecache_action_definition($action['action']);
|
| 1065 |
$action = array_merge($definition, $action);
|
| 1066 |
$actions[$actionid] = $action;
|
| 1067 |
}
|
| 1068 |
}
|
| 1069 |
return $actions[$actionid];
|
| 1070 |
}
|
| 1071 |
|
| 1072 |
function imagecache_action_load($actionid) {
|
| 1073 |
return imagecache_action($actionid, TRUE);
|
| 1074 |
}
|
| 1075 |
|
| 1076 |
function imagecache_action_save($action) {
|
| 1077 |
$definition = imagecache_action_definition($action['action']);
|
| 1078 |
$action = array_merge($definition, $action);
|
| 1079 |
|
| 1080 |
if (!empty($action['actionid'])) {
|
| 1081 |
drupal_write_record('imagecache_action', $action, 'actionid');
|
| 1082 |
}
|
| 1083 |
else {
|
| 1084 |
drupal_write_record('imagecache_action', $action);
|
| 1085 |
}
|
| 1086 |
$preset = imagecache_preset($action['presetid']);
|
| 1087 |
imagecache_preset_flush($preset);
|
| 1088 |
imagecache_presets(TRUE);
|
| 1089 |
return $action;
|
| 1090 |
}
|
| 1091 |
|
| 1092 |
function imagecache_action_delete($action) {
|
| 1093 |
db_query('DELETE FROM {imagecache_action} WHERE actionid=%d', $action['actionid']);
|
| 1094 |
$preset = imagecache_preset($action['presetid']);
|
| 1095 |
imagecache_preset_flush($preset);
|
| 1096 |
imagecache_presets(TRUE);
|
| 1097 |
}
|