'admin/settings/node_images',
'title' => t('Node images'),
'description' => t('Control how to upload node images.'),
'callback' => 'drupal_get_form',
'callback arguments' => array('node_images_admin_settings'),
'access' => $admin
);
$items[] = array('path' => 'admin/build/node_images',
'title' => t('Node images'),
'description' => t('Resize uploaded node images.'),
'callback' => 'drupal_get_form',
'callback arguments' => array('node_images_form_resize'),
'access' => $admin
);
} else {
if (arg(0) == 'node' && is_numeric(arg(1))) {
$node = node_load(arg(1));
if ($node->nid && variable_get('node_images_position_'.$node->type, 'hide') != 'hide') {
$items[] = array(
'path' => 'node/' . arg(1) . '/images',
'title' => t('Images'),
'callback' => '_node_images_edit_form',
'callback arguments' => array($node),
'access' => $access && node_access('update', $node),
'type' => MENU_LOCAL_TASK,
'weight' => 2
);
$items[] = array(
'path' => 'node/' . arg(1) . '/image_gallery',
'title' => t('Gallery'),
'callback' => '_node_images_gallery',
'callback arguments' => array($node),
'access' => node_access('view', $node),
'type' => MENU_CALLBACK
);
}
}
}
$items[] = array(
'path' => 'node_images/js',
'callback' => '_node_images_js',
'access' => $access,
'type' => MENU_CALLBACK
);
return $items;
}
function node_images_form_resize() {
$form['thumbnails'] = array(
'#type' => 'checkbox',
'#title' => t('Resize thumbnails'),
'#default_value' => 0,
'#description' => t('Check if you want to resize the thumbnails images.'),
);
$form['medium'] = array(
'#type' => 'checkbox',
'#title' => t('Resize medium size images'),
'#default_value' => 0,
'#description' => t('Check if you want to resize the medium size images.'),
);
$form['submit'] = array('#type' => 'submit', '#value' => t('Submit'));
return $form;
}
function node_images_form_resize_validate($form_id, $form_values) {
if (!$form_values['thumbnails'] && !$form_values['medium']) {
form_set_error('thumbnails', t('Select at least one type for this to do something'));}
}
function node_images_form_resize_submit($form_id, $form_values) {
$count = node_images_get_images($form_id, $form_values);
$all = $count*2;
if ($form_values['thumbnails'] && $form_values['medium']) {
drupal_set_message(t('You selected to resize both type of images. There were '.$all.' images resized')); }
elseif ($form_values['thumbnails']) {
drupal_set_message(t('You selected to resize thumbnail images. There were '.$count.' images resized')); }
elseif ($form_values['medium']) {
drupal_set_message(t('You selected to resize medium size images. There were '.$count.' images resized')); }
}
function node_images_get_images($form_id, $form_values) {
$result = db_query('SELECT * FROM {node_images}');
while ($images = db_fetch_array($result)){
$i++;
if (is_file($images['filepath'])) {
if ($form_values['thumbnails'] && is_file($images['thumbpath'])) {
file_delete($images['thumbpath']);
}
if ($form_values['medium'] && is_file($images['mediumpath'])) {
file_delete($images['mediumpath']);
}
if ($form_values['thumbnails']) {
$thumb = _node_images_create_thumbnail($images['filepath']);
$images['thumbsize'] = $thumb->filesize;
$images['thumbpath'] = $thumb->filepath; }
if ($form_values['medium']) {
$medium = _node_images_create_medium_size($images['filepath']);
$images['mediumsize'] = $medium->filesize;
$images['mediumpath'] = $medium->filepath; }
db_query('UPDATE {node_images} SET mediumpath = "%s", mediumsize = %d, thumbpath = "%s", thumbsize = %d WHERE id = %d', $images['mediumpath'], $images['mediumsize'], $images['thumbpath'], $images['thumbsize'], $images['id']);
}
}
return $i;
}
/**
* implementation of hook_form_alter()
*/
function node_images_form_alter($form_id, &$form) {
$type = $form['#node_type']->type;
if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
// radio button in the node's content type configuration page
_node_images_check_settings();
$form['node_images'] = array(
'#type' => 'fieldset',
'#title' => t('Node images'),
'#collapsible' => TRUE,
);
$form['node_images']['node_images_position'] = array(
'#type' => 'radios',
'#title' => t('Position'),
'#default_value' => variable_get('node_images_position_'.$type, 'hide'),
'#options' => array('hide' => t('Do not show'), 'above' => t('Show above node body'), 'below' => t('Show below node body'),
'node_template' => t('Manually set in node template by variable $node->node_images')),
'#description' => t('The position of images in the node view.'),
);
$form['node_images']['node_images_gallery_link'] = array(
'#type' => 'radios',
'#title' => t('Link to image gallery'),
'#default_value' => variable_get('node_images_gallery_link_'.$type, TRUE),
'#options' => array(t('Do not show'), t('Show')),
'#description' => t('Choose whether to show or not the link to the image gallery.'),
);
$form['node_images']['node_images_teaser_images'] = array(
'#type' => 'textfield',
'#title' => t('Number of images in node teaser'),
'#default_value' => variable_get('node_images_teaser_images_'.$type, 2),
'#size' => 5,
'#maxlength' => 2,
'#description' => t('The maximum number of images to show in the node teaser. 0 will not show images. Leave blank to show all images.'),
);
$form['node_images']['node_images_body_images'] = array(
'#type' => 'textfield',
'#title' => t('Number of images in node body'),
'#size' => 5,
'#maxlength' => 2,
'#default_value' => variable_get('node_images_body_images_'.$type, NULL),
'#description' => t('The maximum number of images to show in the node body. 0 will not show images. Leave blank to show all images.'),
);
$form['node_images']['node_images_teaser_format'] = array(
'#type' => 'radios',
'#title' => t('Image format in node teaser'),
'#default_value' => variable_get('node_images_teaser_format_'.$type, 'thumbs'),
'#options' => array('thumbs' => t('Thumbnails'), 'medium' => t('Medium size'), 'fullsize' => t('Full size images')),
'#description' => t('Image format in node teaser.'),
);
$form['node_images']['node_images_body_format'] = array(
'#type' => 'radios',
'#title' => t('Image format in node body'),
'#default_value' => variable_get('node_images_body_format_'.$type, 'thumbs'),
'#options' => array('thumbs' => t('Thumbnails'), 'medium' => t('Medium size'), 'fullsize' => t('Full size images')),
'#description' => t('Image format in node body.'),
);
$form['submit']['#weight'] = 30;
$form['delete']['#weight'] = 31;
$form['reset']['#weight'] = 32;
}
}
/**
* Implementation of hook_nodeapi().
*/
function node_images_nodeapi(&$node, $op, $teaser, $page) {
// test if images are allowed for this node
if ($op == 'load' || $op == 'view') {
if (variable_get('node_images_position_'.$node->type, 'hide') == 'hide') return;
// fire an additional hook for the specific node type
// i.e. node images might be a pro feature, so only subscribed users can view them
// if the hook is not present in the node type module, images are loaded by default
$show = module_invoke($node->type, 'node_images', $op, $node);
if ($show === FALSE) return;
}
switch ($op) {
case 'load':
// load node images for the current node
$sql = db_query('SELECT * FROM {node_images} WHERE nid=%d AND status=1 ORDER BY weight', $node->nid);
while ($r = db_fetch_object($sql)) {
$node->node_images[$r->id] = $r;
}
break;
case 'insert':
if (user_access('create node images') && node_access('update', $node) &&
variable_get('node_images_position_'.$node->type, 'hide') != 'hide') {
drupal_set_message(t('Click the !images tab to add images to this node.',
array('!images' => l(t('images'), 'node/'.$node->nid.'/images'))));
}
break;
case 'delete':
// Delete image and thumbnail files
$sql = db_query('SELECT filepath, mediumpath, thumbpath FROM {node_images} WHERE nid=%d', $node->nid);
while ($r = db_fetch_object($sql)) {
file_delete($r->filepath);
file_delete($r->mediumpath);
file_delete($r->thumbpath);
}
// Delete all images associated with the node
db_query('DELETE FROM {node_images} WHERE nid=%d', $node->nid);
break;
case 'view':
if (empty($node->node_images)) return;
// search for a themed view for the current node type
$nodetype_function = 'theme_'.$node->type.'_node_images_view';
if (function_exists($nodetype_function)) {
$output = $nodetype_function($node, $teaser, $page);
}
else {
// use the default theme function
$output = theme('node_images_view', $node, $teaser, $page);
}
$node->node_images = $output;
$output = '
'.$output.'
';
$position = variable_get('node_images_position_'.$node->type, 'hide');
switch ($position) {
case 'node_template':
case 'hide':
break;
case 'above':
$node->content['node_images'] = array('#value' => $output, '#weight' => -1);
break;
default:
$node->content['node_images'] = array('#value' => $output, '#weight' => 1);
break;
}
return $node;
}
}
/**
* Implementation of hook_link().
*/
function node_images_link($type, $node = null, $teaser = false) {
$links = array();
if ($type == 'node' && $node->nid && variable_get('node_images_position_'.$node->type, 'hide') != 'hide') {
if (node_access('update', $node) && user_access('create node images')) {
$links['node_images_edit'] = array(
'title' => t('Edit node images'),
'href' => "node/$node->nid/images",
);
}
if (count($node->node_images) && variable_get('node_images_gallery_link_'.$node->type, TRUE)) {
$links['node_images_gallery'] = array(
'title' => t('Open the image gallery'),
'href' => "node/$node->nid/image_gallery",
);
}
}
return $links;
}
/**
* Implementation of hook_user().
*/
function node_images_user($type, &$edit, &$user, $category = NULL) {
switch ($type) {
case 'delete':
// Set uid=0 for images uploaded by the deleted user
db_query('UPDATE {node_images} SET uid=0 WHERE uid=%d', $user->uid);
}
}
/**
* Implementation of hook_file_download().
* Find out if an image is accessible when download method is set to private
*/
function node_images_file_download($file) {
$path = file_create_path($file);
$result = db_query("SELECT * FROM {node_images} WHERE filepath='%s' OR thumbpath='%s' OR mediumpath='%s'", $path, $path, $path);
if ($file = db_fetch_object($result)) {
$node = node_load($file->nid);
if (node_access('view', $node)) {
if ($path == $file->thumbpath) {
// update header info if thumb is requested
$name = mime_header_encode(basename($file->thumbpath));
$size = $file->thumbsize;
}
elseif ($path == $file->mediumpath) {
// update header info if medium size is requested
$name = mime_header_encode(basename($file->mediumpath));
$size = $file->mediumsize;
}
else {
$name = mime_header_encode($file->filename);
$size = $file->filesize;
}
$type = mime_header_encode($file->filemime);
return array(
'Content-Type: '. $type .'; name='. $name,
'Content-Length: '. $size,
'Cache-Control: private'
);
}
else {
return -1;
}
}
}
/************************************************************
* Node edit functions
************************************************************/
/**
* Display the page to edit and upload node images.
*
* @param $node
* the current node
* @return
* the node images page.
*/
function _node_images_edit_form($node) {
global $user;
$output = '
';
// Generate image list
$sql = db_query('SELECT * FROM {node_images} WHERE nid=%d ORDER BY weight', $node->nid);
if (db_num_rows($sql)>0) $output .= drupal_get_form('_node_images_list', $node, $sql);
// test if this node can accept new images
// i.e. there might be limits to the number of uploaded images for certain node types or user roles
// if the hook is not present in the node type module, upload is enabled by default
$upload = module_invoke($node->type, 'node_images', 'upload', $node);
if ($upload !== FALSE) {
$output .= drupal_get_form('_node_images_edit_form_upload', $node);
}
$output .= '
';
drupal_set_title(check_plain($node->title));
return $output;
}
function _node_images_edit_form_upload($node) {
$path = variable_get('node_images_path', 'files');
_node_images_check_directory(NULL, $path);
$extensions = variable_get('node_images_extensions', 'jpg jpeg gif png');
drupal_add_js('misc/progress.js');
drupal_add_js('misc/upload.js');
// Generate upload form
$form['new'] = array(
'#type'=>'fieldset',
'#title'=>t('Upload a new image'),
);
$form['new']['description'] = array(
'#type' => 'textfield',
'#title' => t('Description'),
'#size' => 50,
'#maxlength' => 255,
'#default_value' => $edit['new']['description'],
'#description' => t('Enter a description for the new image, max 255 chars.'),
'#prefix' => '
';
return $output;
}
/************************************************************
* Helper functions - admin settings
************************************************************/
/**
* Menu callback; admin settings page.
*/
function node_images_admin_settings() {
_node_images_check_settings();
$form['node_images_path'] = array(
'#type' => 'textfield',
'#title' => t('Node images path'),
'#default_value' => variable_get('node_images_path', 'files'),
'#maxlength' => 255,
'#description' => t('A file system path where the node images will be stored. This directory has to exist and be writable by Drupal. You can use the following variables: %uid, %username'),
'#after_build' => array('_node_images_check_directory'),
);
$form['node_images_thumb_resolution'] = array(
'#type' => 'textfield',
'#title' => t('Resolution for thumbnails'),
'#default_value' => variable_get('node_images_thumb_resolution', '100x100'),
'#size' => 15,
'#maxlength' => 7,
'#description' => t('The thumbnail size expressed as WIDTHxHEIGHT (e.g. 100x75).'),
);
$form['node_images_medium_resolution'] = array(
'#type' => 'textfield',
'#title' => t('Resolution for medium image size'),
'#default_value' => variable_get('node_images_medium_resolution', '200x200'),
'#size' => 15,
'#maxlength' => 7,
'#description' => t('The thumbnail size expressed as WIDTHxHEIGHT (e.g. 200x150).'),
);
$form['node_images_extensions'] = array(
'#type' => 'textfield',
'#title' => t('Default permitted image extensions'),
'#default_value' => variable_get('node_images_extensions', 'jpg jpeg gif png'),
'#maxlength' => 255,
'#description' => t('Default image extensions that users can upload. Separate extensions with a space and do not include the leading dot.'),
);
$form['node_images_max_images'] = array(
'#type' => 'textfield',
'#title' => t('Maximum number of images'),
'#default_value' => variable_get('node_images_max_images', 4),
'#size' => 6,
'#maxlength' => 2,
'#description' => t('The maximum number of images a user can upload for each node.'),
);
$form['node_images_md5name'] = array(
'#type' => 'checkbox',
'#title'=> t('MD5 filenames'),
'#description' => t('Override uploaded filenames with the MD5 hash of the file.'),
'#default_value' => variable_get('node_images_md5name', FALSE),
);
return system_settings_form($form);
}
/**
* Checks if the upload.module is enabled, and the existence of an image toolkit.
*
* @param $form_element
* The form element containing the name of the directory to check.
*/
function _node_images_check_settings() {
// Make sure upload module is enabled
if (!module_exists('upload')) {
drupal_set_message(t('node_images.module require upload.module to be enabled.'), 'error');
}
// Make sure we've got a working toolkit
if (!image_get_toolkit()) {
drupal_set_message(t('Make sure you have a working image toolkit installed and enabled, for more information see: %settings', array('%settings' => l(t('the settings page'), 'admin/settings/image-toolkit'))), 'error');
}
}
/************************************************************
* Helper functions - other
************************************************************/
/**
* Checks the existence of the destination directory.
* The directory can be specified either in $form_element (when called from the admin settings)
* or in $path (when called from the node images edit page).
*
* @param $form_element
* The form element containing the name of the directory to check.
*/
function _node_images_check_directory($form_element = NULL, $path = '') {
global $user;
$variables = array('%uid' => $user->uid, '%username' => $user->name);
if ($form_element) {
$path = strtr($form_element['#value'], $variables);
_node_images_mkdir_recursive($path, FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
return $form_element;
}
$path = strtr($path, $variables);
_node_images_mkdir_recursive($path, FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
}
function _node_images_mkdir_recursive($path, $mode, $form_item) {
$folders = explode("/", $path);
$dirs = array();
foreach($folders as $folder) {
$dirs[] = $folder;
if (!file_check_directory(implode("/", $dirs), $mode, $form_item)) {
mkdir(implode("/", $dirs));
}
}
}
/**
* Return the destination directory.
*/
function _node_images_get_directory() {
global $user;
$path = variable_get('node_images_path', 'files');
return strtr($path, array('%uid' => $user->uid, '%username' => $user->name));
}
/**
* Create the thumbnail for the uploaded image.
*/
function _node_images_create_thumbnail($path, $suffix='_tn') {
$size = variable_get('node_images_thumb_resolution', '100x100');
list($width, $height) = explode('x', $size);
$dest_path = preg_replace('!(\.[^/.]+?)?$!', "$suffix\\1", $path, 1);
if ($size = getimagesize($path)) {
image_scale($path, $dest_path, $width, $height);
$info = image_get_info($dest_path);
$thumb = new stdClass();
$thumb->filename = basename($dest_path);
$thumb->filepath = $dest_path;
$thumb->filesize = $info['file_size'];
$thumb->filemime = $info['mime_type'];
return $thumb;
}
return NULL;
}
/**
* Create the full size image for the uploaded image.
*/
function _node_images_create_medium_size($path, $suffix='_md') {
$size = variable_get('node_images_medium_resolution', '200x200');
list($width, $height) = explode('x', $size);
$dest_path = preg_replace('!(\.[^/.]+?)?$!', "$suffix\\1", $path, 1);
if ($size = getimagesize($path)) {
image_scale($path, $dest_path, $width, $height);
$info = image_get_info($dest_path);
$medium = new stdClass();
$medium->filename = basename($dest_path);
$medium->filepath = $dest_path;
$medium->filesize = $info['file_size'];
$medium->filemime = $info['mime_type'];
return $medium;
}
return NULL;
}
/**
* Determine how much disk space is occupied by a user's uploaded files.
*
* @param $uid
* The integer user id of a user.
* @return
* The amount of disk space used by the user in bytes.
*/
function _node_images_space_used($uid) {
return db_result(db_query('SELECT SUM(filesize+thumbsize) FROM {node_images} WHERE uid=%d', $uid));
}
/**
* Menu-callback for JavaScript-based uploads.
*/
function _node_images_js() {
$edit = $_POST;
if ($nid = $edit['nid']) {
$node = node_load($nid);
// upload image
_node_images_upload($edit, $node);
// generate node images edit page
$form = _node_images_edit_form($node);
} else {
drupal_set_message(t('Unable to attach images to the current node.'));
}
$output = theme('status_messages');
if ($form) $output .= $form;
// We send the updated file attachments form.
print drupal_to_js(array('status' => TRUE, 'data' => $output));
exit();
}
/************************************************************
* Views API hooks
************************************************************/
/**
* Implementation of hook_views_default_tables().
*/
function node_images_views_tables() {
require_once './'. drupal_get_path('module', 'node_images') .'/node_images.views.inc';
return _node_images_views_tables();
}
/**
* Implementation of hook_views_pre_query().
*/
function node_images_views_pre_query() {
require_once './'. drupal_get_path('module', 'node_images') .'/node_images.views.inc';
}