Пример #1
0
/**
 * Render markup for an image tag in smarty
 *
 * The {img} smarty function is the recommended way to load images in templates from asset or public directories.
 * In addition to automatically resolving URLs, it can also handle server-side resizing and a few other nifty features.
 *
 * #### Image Types & Animations
 *
 * As of Core 3.3.0, image types are preserved, so if a .jpg is requested, an image/jpeg is returned.
 * This changed from the previous behaviour where all images were converted to a PNG.
 *
 * Supported image types are `.jp[e]g`, `.png`, and `.gif`.
 *
 * If an animated gif is resized, the server will attempt to preserve the animation on the resized image.
 * This is done via imagemagick, (so that library needs to be present on the server in order for this trick to work).
 *
 * #### SEO Data
 *
 * As of Core 3.2.0, alt tags are automatically added to every image that does not have the alt attribute explicitly set.
 * This alt name is pulled from the filename of the image, with automatic capitalization and '_' => (space) converting.
 *
 * #### Smarty Parameters
 *
 *  * assign
 *    * string
 *    * Set to a string to assign that variable name instead of returning the output.
 *  * dimensions
 *    * Provide both width and height in pixels, along with special instructions
 *    * Structure is "widthxheight" with no spaces between the "x" and the two integers.
 *    * Special modes available are:
 *    * Carat "`^`" at the end of the string fits the smallest dimension instead of the largest.
 *    * Exclamation mark "`!`" at the end forces size regardless of aspect ratio.
 *    * Greater than "`>`" at the end will only increase image sizes.
 *    * Less than "`<`" at the end will only decrease image sizes.
 *  * file
 *    * \Core\Filestore\File
 *    * File object passed in to display
 *    * Either "file" or "src" is required.
 *  * height
 *    * int
 *    * Maximum image height (in pixels).
 *    * If both width and height are provided, the image will be constrained to both without any distortion.
 *  * inline
 *    * int "1" or "0", (default "0")
 *    * New in Core 4.2.0
 *    * Request that the resized image be encoded as base64 and inserted inline in the markdown instead of returned as the URL.
 *  * placeholder
 *    * string
 *    * placeholder image if the requested image is blank or not found.  Useful for optional fields that should still display something.
 *    * Current values: "building", "generic", "person", "person-tall", "person-wide", "photo"
 *  * src
 *    * string
 *    * Source filename to display.  This can start with "assets" for an asset, or "public" for a public file.
 *    * Either "file" or "src" is required.
 *  * width
 *    * int
 *    * Maximum image width (in pixels).
 *    * If both width and height are provided, the image will be constrained to both without any distortion.
 *
 * Any other parameter is transparently sent to the resulting `<img/>` tag.
 *
 *
 * #### Example Usage
 *
 * <pre>
 * {img src="public/gallery/photo123.png" width="123" height="123" placeholder="photo" alt="My photo 123"}
 * </pre>
 *
 * @param array  $params  Associative (and/or indexed) array of smarty parameters passed in from the template
 * @param Smarty $smarty  Parent Smarty template object
 *
 * @return string
 * @throws SmartyException
 */
function smarty_function_img($params, $smarty){

	// Key/value array of attributes for the resulting HTML.
	$attributes = array();

	if(isset($params['file'])){
		$f = $params['file'];
		if(!$f instanceof \Core\Filestore\File){
			throw new SmartyException('{img} tag expects a \Core\Filestore\File object for the "file" parameter.');
		}
		unset($params['file']);
	}
	elseif(isset($params['src'])){
		$f = \Core\Filestore\Factory::File($params['src']);
		unset($params['src']);
	}
	else{
		$f = null;
	}

	// Some optional parameters, (and their defaults)
	$assign = $width = $height = $dimensions = $inline = false;
	$placeholder = $previewfile = null;

	if(isset($params['assign'])){
		$assign = $params['assign'];
		unset($params['assign']);
	}

	if(isset($params['width'])){
		$width = $params['width'];
		unset($params['width']);
	}

	if(isset($params['height'])){
		$height = $params['height'];
		unset($params['height']);
	}

	if(isset($params['dimensions'])){
		$dimensions = $params['dimensions'];
		$width = preg_replace('#[^0-9]?([0-9]*)x.*#', '$1', $dimensions);
		$height = preg_replace('#.*x([0-9]*)[^0-9]?#', '$1', $dimensions);
		unset($params['dimensions']);
	}

	if(isset($params['placeholder'])){
		$placeholder = $params['placeholder'];
		unset($params['placeholder']);
	}

	if(isset($params['inline'])){
		$inline = ($params['inline'] == '1');
		unset($params['inline']);
	}


	if($dimensions){
		// Passing in dimensions raw will allow the user more control over the size of the images.
		$d = $dimensions;
	}
	else{
		// If one is provided but not the other, just make them the same.
		if($width && !$height) $height = $width;
		if($height && !$width) $width = $height;

		$d = ($width && $height) ? $width . 'x' . $height : false;
	}

	// If the file doesn't exist and a placeholder was provided, use the appropriate placeholder image!
	if(!($f && $f->exists() && $f->isImage()) && $placeholder){
		// Try that!
		$f = \Core\Filestore\Factory::File('assets/images/placeholders/' . $placeholder . '.png');
	}

	if(!$f){
		throw new SmartyException('{img} tag requires either "src", "file", or a "placeholder" parameter.');
	}

	// Do the rest of the attributes that the user sent in (if there are any)
	foreach($params as $k => $v){
		$attributes[$k] = $v;
	}

	if($f instanceof Core\Filestore\Backends\FileRemote){
		// Erm... Give the original URL with the dimension requests.
		$attributes['src'] = $f->getURL();
		if($width) $attributes['width'] = $width;
		if($height) $attributes['height'] = $height;
	}
	else{
		// Try to lookup the preview file.
		// if it exists, then YAY... I can return that direct resource.
		// otherwise, I should check and see if the file is larger than a set filesize.
		// if it is, then I want to return a link to a controller to render that file instead of rendering the file from within the {img} tag.
		//
		// This is useful because any logic contained within this block will halt page execution!
		// To improve the perception of performance, that can be offloaded to the browser requesting the <img/> contents.
		$previewfile = $d ? $f->getQuickPreviewFile($d) : $f;

		if(!$previewfile){
			$attributes['src'] = '#';
			$attributes['title'] = 'No preview files available!';
		}
		elseif($inline && $f->getFilesize() < 1048576*4){
			// Overwrite the src attribute with the base64 contents.
			// This can only happen after the preview file exists!

			if(!$previewfile->exists()){
				// Since quick ran, ensure that it's actually resized!
				$previewfile = $f->getPreviewFile($d);
			}
			$attributes['src'] = 'data:' . $previewfile->getMimetype() . ';base64,' . base64_encode($previewfile->getContents());
		}
		elseif(!$previewfile->exists()){
			// Ok, it doesn't exist... return a link to the controller to render this file.
			$attributes['src'] = \Core\resolve_link('/file/preview') . '?f=' . $f->getFilenameHash() . '&d=' . $d;
		}
		else{
			$attributes['src'] = $previewfile->getURL();
		}
	}

	// All images need alt data!
	if(!isset($attributes['alt'])){
		$attributes['alt'] = $f->getTitle();
	}

	// Merge them back together in one string.
	$html = '<img';
	foreach($attributes as $k => $v) $html .= " $k=\"$v\"";
	$html .= '/>';

	// If the extended metadata was requested... look that up too!
	if(isset($params['includemeta']) && $params['includemeta']){

		$metahelper  = new \Core\Filestore\FileMetaHelper($f);
		$metacontent = $metahelper->getAsHTML();
		if($metacontent){
			$html = '<div class="image-metadata-wrapper">' . $html . $metacontent . '</div>';
		}
	}

	return $assign ? $smarty->assign($assign, $html) : $html;
}
Пример #2
0
 public static function ImagesUpdateSaveHandler(Form $form)
 {
     try {
         /** @var $image GalleryImageModel */
         $image = $form->getModel('image');
     } catch (Exception $e) {
         Core::SetMessage($e->getMessage(), 'error');
         return false;
     }
     $metas = new \Core\Filestore\FileMetaHelper($image->getOriginalFile());
     // Set the meta information from the form.
     foreach ($form->getElements() as $el) {
         /** @var $el FormElement */
         $name = $el->get('name');
         if (strpos($name, 'metas[') !== 0) {
             continue;
         }
         $name = substr($name, 6, -1);
         $metas->setMeta($name, $el->get('value'));
     }
     // If no title was set, I need to pick one by default.
     if (!$metas->getMetaTitle('title')) {
         // Generate a moderately meaningful title from the filename.
         $title = $image->getOriginalFile()->getBasename(true);
         $title = preg_replace('/[^a-zA-Z0-9 ]/', ' ', $title);
         $title = trim(preg_replace('/[ ]+/', ' ', $title));
         $title = ucwords($title);
         $metas->setMeta('title', $title);
     }
     if (!$image->exists()) {
         // Figure out the largest weight of this album.
         // Note, this is NOT the size of the images, as one or more may have been deleted after uploading.
         $last = GalleryImageModel::Find(array('albumid' => $image->get('albumid')), 1, 'weight DESC');
         $weight = $last ? $last->get('weight') : 0;
         $image->set('weight', $weight);
     }
     // Don't forget to keep the metatags in sync!
     $image->set('title', $metas->getMetaTitle('title'));
     $action = $image->exists() ? 'Updated' : 'Added';
     $image->save();
     Core::SetMessage($action . ' image successfully!', 'success');
     return true;
 }
Пример #3
0
/**
 * Utility to Core-ify a given HTML string.
 *
 * Will use a tokenizer to scan for <img /> tags and <a /> tags.
 *
 * @param $html
 * @return string
 */
function parse_html($html){
	// Counter for the current position of the tokenizer.
	$x = 0;
	// Set to the position of the current image
	$imagestart = null;

	// @todo a rel=nofollow tags for external/untrusted links
	//       This can make use of an external utility to allow the admin to set which links are allowed.

	// @todo a tags that are absolutely resolved or have a core prefix such as core:///about-us or what not.

	while($x < strlen($html)){
		// Replace images with the optimized version.
		if(substr($html, $x, 4) == '<img'){
			$imagestart = $x;
			$x+= 3;
			continue;
		}

		$fullimagetag = null;

		if($imagestart !== null && $html{$x} == '>'){
			// This will equal the full image HTML tag, ie: <img src="blah"/>...
			$fullimagetag = substr($html, $imagestart, $x-$imagestart+1);
		}
		elseif($imagestart !== null && substr($html, $x, 2) == '/>'){
			// This will equal the full image HTML tag, ie: <img src="blah"/>...
			$fullimagetag = substr($html, $imagestart, $x-$imagestart+2);
		}

		if($imagestart !== null && $fullimagetag){
			// Convert it to a DOM element so I can process it.
			$simple = new \SimpleXMLElement($fullimagetag);
			$attributes = array();
			foreach($simple->attributes() as $k => $v){
				$attributes[$k] = (string)$v;
			}

			$file = \Core\Filestore\Factory::File($attributes['src']);

			// All images need alt tags.
			if(!isset($attributes['alt']) || $attributes['alt'] == ''){
				// Since this is usually only used to render content and the images contained therein,
				// and tinymce auto-adds a blank alt="" attribute,
				// I can safely add the alt based on the file's rendered title.
				$attributes['alt'] = $file->getTitle();
			}

			if(isset($attributes['width']) || isset($attributes['height'])){

				if(isset($attributes['width']) && isset($attributes['height'])){
					$dimension = $attributes['width'] . 'x' . $attributes['height'] . '!';
					unset($attributes['width'], $attributes['height']);
				}
				elseif(isset($attributes['width'])){
					$dimension = $attributes['width'];
					unset($attributes['width']);
				}
				else{
					$dimension = $attributes['height'];
					unset($attributes['height']);
				}

				$attributes['src'] = $file->getPreviewURL($dimension);
			}

			// And rebuild.
			$img = '<img';
			foreach($attributes as $k => $v){
				$img .= ' ' . $k . '="' . str_replace('"', '&quot;', $v) . '"';
			}
			$img .= '/>';

			$metahelper  = new \Core\Filestore\FileMetaHelper($file);
			$metacontent = $metahelper->getAsHTML();
			if($metacontent){
				$img = '<div class="image-metadata-wrapper">' . $img . $metacontent . '</div>';
			}

			// Figure out the offset for X.  I'll need to modify this after I merge it in.
			$x += strlen($img) - strlen($fullimagetag);
			// Split this string back in.
			$html = substr_replace($html, $img, $imagestart, strlen($fullimagetag));

			// Reset...
			$imagestart = null;
		}
		$x++;
	}
	//var_dump($html);

	return $html;
}
 /**
  * Save handler for the form_metadata page.
  *
  * @param Form $form
  */
 public static function FileMetadataSaveHandler(Form $form)
 {
     $filename = $form->getElement('file')->get('value');
     $file = \Core\Filestore\Factory::File($filename);
     $helper = new \Core\Filestore\FileMetaHelper($file);
     // Run through each element and save its metadata to the table.
     foreach ($form->getElements() as $el) {
         /** @var $el FormElement */
         $name = $el->get('name');
         if ($name == 'file') {
             continue;
         }
         if ($name == '___formid') {
             continue;
         }
         if ($name == 'submit') {
             continue;
         }
         $helper->setMeta($name, $el->get('value'));
     }
     return true;
 }
/**
 * Created by JetBrains PhpStorm.
 * User: powellc
 * Date: 1/17/13
 * Time: 10:20 PM
 * This is the upgrade file from 1.4.3 to 1.4.4
 *
 * Required because with the file input change in 2.6.0 returning core resolved paths,
 * the data in the database will contain that path now.
 */
$images = GalleryImageModel::Find();
foreach ($images as $i) {
    /** @var $i GalleryImageModel */
    // Just in case
    if (strpos($i->get('file'), 'public/') !== 0) {
        $i->set('file', 'public/galleryalbum/' . $i->get('file'));
        $i->save();
    }
    // Don't forget to copy over the meta data too!
    // This is because the gallery system will use the new version of metadata.
    $u = UserModel::Construct($i->get('uploaderid'));
    $helper = new \Core\Filestore\FileMetaHelper($i->getOriginalFile());
    $helper->setMeta('title', $i->get('title'));
    $helper->setMeta('keywords', explode(',', $i->get('keywords')));
    $helper->setMeta('description', $i->get('description'));
    $helper->setMeta('authorid', $i->get('uploaderid'));
    if ($u && $u instanceof User_Backend) {
        $helper->setMeta('author', $u->getDisplayName());
    }
}