<?php if (!defined('PmWiki')) exit(); /** A thumbnail gallery generator for PmWiki Written by (c) Petko Yotov 2006-2008 This script is POSTCARDWARE, if you like it or use it, please send me a postcard. Details at http://galleries.accent.bg/Thumblist2 This text is written for PmWiki; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. See pmwiki.php for full details and lack of warranty. Copyright 2006-2008 Petko Yotov http://5ko.fr Copyright 2004-2006 Patrick R. Michaud http://www.pmwiki.org Copyright 2006 Hagan Fox (haganfoxATusersDOTsourceforge.net) */ # Version date $RecipeInfo['ThumbList']['Version'] = '20081015'; $FmtPV['$ThumbListVersion'] = "'TL-{$RecipeInfo['ThumbList']['Version']}'"; SDVA($ThumbList, array( 'Px' => 128, 'HTMLpx'=> 1, 'TrailPx' => 64,'TableCols' => 0, 'tlmode'=> 0, 'TitleFormat' => "?f: ?wx?h, ?kk (?t)", 'CaptionFormat' => '', 'LinkRel' => '','BgColor' => "#ffffff",#for transparent pictures 'LinkOriginal' => 0,# 1:always; -1:never; 0:when needed; 2:link to page 'UseTmpl' => 0, 'AllowedUploadPages' => '*', 'ShowErrors' => 1, 'AttachLinks' => 1, 'FileExt' => 'jpg', 'FileListOrder' => 'name', 'ImTypes' => array(1=>"gif",2=>"jpeg",3=>"png",15=>"wbmp",16=>"xbm"), 'ImTypesRegExp' => "\\.(?:jpe?g|png|gif|jpe|wbmp|xbm)", 'EnableMarkup'=> 1, 'EnableThumbs'=> 1, # functions 'fGetFileList'=> 'ThumbGetFileList','fOrderFileList'=> 'ThumbOrderFileList', 'fGetFileStat'=> 'ThumbGetFileStat', 'fEXIF'=> 'ThumbExif', 'fPreChecks'=> null, )); SDVA($ThumbList['OrderFunctions'], array( 'ext' => 'return strnatcmp($a["ext"], $b["ext"]);', 'name' => 'return strnatcmp($a["name"], $b["name"]);', 'random' => 'return mt_rand(-1,1);', 'time' => 'return $a["stat"][9] - $b["stat"][9];', 'size' => 'return $a["stat"][7] - $b["stat"][7];', 'width' => 'return $a["getimagesize"][0] - $b["getimagesize"][0];', 'height' => 'return $a["getimagesize"][1] - $b["getimagesize"][1];', 'ratio' => '$c=$a["getimagesize"];$d=$b["getimagesize"]; return round(($c[0]/$c[1]-$d[0]/$d[1])*10000);', )); SDVA($ThumbList['stat_dirlist'], array( 'time'=>'stat','size'=>'stat','width'=>'getimagesize', 'height'=>'getimagesize','ratio'=>'getimagesize', )); SDVA($ThumbList['_tmpl'], array( 'tableattributes' => array("border", "cellpadding", "cellspacing", "rules", "style", "bgcolor", "align"), 'imgwrap' => '<img class="thumbs" src="?u" title="%1$s" alt="%1$s" %2$s border="0"/>', 'awrap' => "<a href='?L' class='thumblink' title='?f' %2\$s>%1\$s</a> ", 'captionwrap'=>'<span class="caption">%s</span>', # %s= awrap, captionwrap, td attr, divattr 'cellwrap'=> "<td class='thumbtd' align='center' valign='top' %3\$s><div class='img' %4\$s>%1\$s</div>%2\$s</td>", 'inlinewrap'=>'%s%s',#%s= img/, <span class=caption> 'inlinewrapall'=>'<span class="thumblist">%s</span>', 'rowwrap'=> "<tr class='thumbtr'>%s</tr>",#%s= cellwrap 'tablewrap'=> "<table %s>%s%s</table>",#%s= table attributes, [tcaption], tbody )); if(preg_match("/^(imgtpl|purgethumbs|createthumb)$/", $action)) { include_once(dirname(__FILE__) . "/thumblist2-actions.php" ); } # Trying to recover existing deprecated configurations... foreach($ThumbList as $k=>$v){$x = "Thumb$k";if(isset($$x)) $ThumbList[$k] = $$x;} if(isset($ThumbListUseTmpl))$ThumbList['UseTmpl'] = $ThumbListUseTmpl; if(isset($ImageTemplateFmt))$ThumbList['ImageTplFmt'] = $ImageTemplateFmt; function percent2qm(&$x){$x = preg_replace("/([^%]|^)%([MmWHTEFAICGfwhbktUuLnN])/", "$1?$2", $x);} # ...Do not rely on this, by 2008 it will be removed! Markup('thumblist', '<split', '/\\(:thumb(list)?\\s*(.*?):\\)/ei', "FmtThumbList(\$pagename,PSS('$2'),'$1')"); Markup('thumbgallery', '<thumblist', '/\\(:thumb(gallery)\\s*(.*?):\\)(.*?)\\(:thumbgalleryend:\\)/esi', "FmtThumbList(\$pagename,PSS('$2'),'$1', PSS('$3'))"); function FmtThumbList($pagename, $args, $suffix='', $list='') { if(! function_exists('imagecreate') && ! $ThumbList['ImageMagickExe']) return ThumbReturn("PHP-GD image library not found. Exiting.", 2); global $UploadDir, $UploadPrefixFmt, $UploadUrlFmt, $TimeFmt, $EnableDirectDownload, $ThumbList, $ThumbList_ShowErrors, $HandleActions, $RecipeInfo, $GroupPattern, $NamePattern; static $ThumbGalNumBase = 0; $ThumbGalNumBase++; $opt = ParseArgs($args); if(@$opt['id'])$ThumbList['IDs'][$opt['id']] = $ThumbGalNumBase; if(function_exists($ThumbList['fPreChecks']))$ThumbList['fPreChecks']($opt); $currentpage = $pagename = MakePageName($pagename, $pagename); $captionfmt =IsEnabled($opt['captionfmt'], $ThumbList['CaptionFormat']); $titlefmt = IsEnabled($opt['titlefmt'], $ThumbList['TitleFormat']); percent2qm($captionfmt); percent2qm($titlefmt); $quiet = intval(@$opt['quiet']);#1:errors 2:attachlinks $ThumbList_ShowErrors = $ThumbList['ShowErrors']; if($quiet%2 == 1)$ThumbList_ShowErrors=0; if($suffix){if (@$opt[''][0]) $pagename = MakePageName($pagename, $opt[''][0]);} else# "thumb" was used { if (! @$opt[''][0]) return ThumbReturn("No file specified.", 1); if(preg_match("!^(.*)\\/([^\\/]+)$!", $opt[''][0], $m) ) { $pagename = MakePageName($pagename, $m[1]); $opt['name'] = $m[2]; } else $opt['name'] = $opt[''][0]; if($captionfmt)$opt['cols'] = $Width = 1; else $opt['cols'] = 0; } $pagelist = MatchPageNames($pagename, FmtPageName($ThumbList['AllowedUploadPages'], $currentpage)); if( @$pagelist[0] == '' ) { return ThumbReturn("$pagename does not match \$ThumbList['AllowedUploadPages'] permissions.", 1); } if ($pagename != $currentpage && !CondAuth($pagename,"read") ) { return ThumbReturn("No read permissions at $pagename.", 1); } $opt['currentpage'] = $currentpage; $opt['pagename'] = $pagename; $supercache = intval(@$opt['supercache']); $ThumbGalNum = $opt['?G'] = ($supercache>999)? $supercache : $ThumbGalNumBase; $ThumbGalNumGet = @isset($ThumbList['IDs']["{$opt['usetemplate']}"]) ? $ThumbList['IDs']["{$opt['usetemplate']}"] : $ThumbGalNum; if(!@$_POST['preview'] && $supercache) { $output = ThumbGetCache($currentpage, $pagename, $ThumbGalNum); if($output) return ThumbReturn($output); } $thumbext = IsEnabled($opt['ext'], $ThumbList['FileExt']); if (intval(@$opt['px']) > 0 ) $Px = intval($opt['px']); elseif(intval(@$opt['width']))$Px = $Width = intval($opt['width']); elseif(intval(@$opt['height'])){$Px = $Height = intval($opt['height']);$Width=0;} elseif(@$ThumbList['Width'])$Px = $Width = $ThumbList['Width']; else $Px = $ThumbList['Px']; $linkorig = IsEnabled($opt['link'], $ThumbList['LinkOriginal']); $linkrel = htmlspecialchars(IsEnabled($opt['rel'], $ThumbList['LinkRel']), ENT_QUOTES); $linktarget = htmlspecialchars(IsEnabled($opt['target'], @$ThumbList['LinkTarget']), ENT_QUOTES); $usetpl =IsEnabled($opt['usetemplate'],$ThumbList['UseTmpl']); $trailstamp = intval($usetpl)>0? ThumbGetCache($currentpage, $pagename, $ThumbGalNum, 2) : 0; $trail = ''; $trailcache = ($trailstamp>0)? 0:1; $thumbcols = IsEnabled($opt['cols'], $ThumbList['TableCols']); $caption = @$opt['caption']; $enableexif = (function_exists($ThumbList['fEXIF']) && function_exists("exif_read_data") && (preg_match("/([^\\?]|^)(\\?\\?)*\\?[MmWHTEFAIC]/", $titlefmt.$captionfmt) || @$opt['onlysetpagevars']>'')); $imcl = (@$opt['imcl']>'' && isset($ThumbList['IMCLTpl'][$opt['imcl']]))? $opt['imcl'] : ''; $tlmode = IsEnabled($opt['tlmode'], $ThumbList['tlmode']); $uploaddir = FmtPageName("$UploadDir$UploadPrefixFmt", $pagename); $uploadurl = FmtPageName(IsEnabled($EnableDirectDownload, 1) ? "$UploadUrlFmt$UploadPrefixFmt/" : "\$PageUrl?action=download&upname=", $pagename); $filelist = array(); if(!$suffix) $filelist[$opt['name']] = $ThumbList['fGetFileStat']($uploaddir, $opt['name'], $opt); elseif($suffix=='list' || $tlmode>0 ) $filelist = $ThumbList['fGetFileList']($uploaddir, $opt); if($suffix=='gallery') { $tem = $ThumbList['EnableMarkup']; $rx = ($tem)? "(?:\"([^\"]*)\")? *(?:\\| *([^\n]+?) *)?" : " *(?:\\| *([^\\|\n]+?) *(?:\\| *(.*) *)?)?"; preg_match_all("/^\s*(.+?{$ThumbList['ImTypesRegExp']})$rx$/im", $list, $m, PREG_SET_ORDER); for($i=0; $i<count($m); $i++) { if($tem)@list(, $_n, $_t, $_c) = $m[$i]; else @list(, $_n, $_c, $_t) = $m[$i]; $filelist[$_n] = $ThumbList['fGetFileStat']($uploaddir, $_n, $opt); $filelist[$_n]['_c'] = $_c; $filelist[$_n]['_t'] = $_t; if(!@$opt['order'] && $tlmode<=0) $opt['order'] = 'none'; } } # rm blocked items by fGetFileStat foreach($filelist as $k=>$a)if(!is_array($a))unset($filelist[$k]); if(!count($filelist) ) return ThumbReturn("No pictures found.", 1); if(IsEnabled($opt['shuffle'], 0))$opt['order'] = 'random'; if(@$opt['order'] == 'random') { ThumbCacheName($opt['currentpage'], $pagename, $opt['?G'], 1, 1); NoCache(); } if(!@$opt['order'])$opt['order'] = $ThumbList['FileListOrder']; $filelist = $ThumbList['fOrderFileList']($filelist, $opt, $uploaddir); $start=1;$limit=count($filelist);#first:last if(@$opt['count']>'') { if(preg_match("/^(\\d+)..(\\d+)$/", $opt['count'], $m)) { $start= max(min($m[1],$m[2]),1); $limit= min(max($m[1],$m[2]),count($filelist))-$start+1; } elseif(preg_match("/^(\\d+)..$/", $opt['count'], $m))$start = $m[1]; elseif(preg_match("/^(..)?(\\d+)$/", $opt['count'], $m)) { $start = 1; $limit= $m[2]; } } if(intval(@$opt['start']>0)) $start=$opt['start']; if(intval(@$opt['limit']>0)) $limit=$opt['limit']; if($start>1||$limit>0) { $f2 = array_slice(array_keys($filelist), $start-1, $limit); $f3 = array();foreach($f2 as $v) {$f3[$v] = $filelist[$v];} if(count($f2)<1) return ThumbReturn("Count out of range.", 1); $filelist=$f3; } if($tlmode==2) { $r = ''; foreach($filelist as $k=>$a) { $t=(@$a['_t']>'')?'"'.$a['_t'].'"':''; $r .= @"$k$t | {$a['_c']}\n";} return Keep(ThumbReturn("<pre>$r</pre>")); } $mybgcolor = preg_match("/^#([0-9a-f]{6}|none)$/i", @$opt['bgcolor']) ? $opt['bgcolor'] : $ThumbList['BgColor']; $htmlpx = IsEnabled($opt['htmlpx'], $ThumbList['HTMLpx']); if($thumbcols) { $mytabattr = ""; foreach($ThumbList['_tmpl']['tableattributes'] as $k) { if(isset($opt[$k])) $mytabattr.=" $k=\"".htmlspecialchars($opt[$k])."\"";} $Px4 = $Px+4; $h = (@$Width)? '' : " height='$Px4'"; $w = (@$Height)? '' : " width='$Px4'"; $pad = (@$Width || @$Height)? '2px' : '%dpx'; $class = @$opt['class']? $opt['class'] : 'thumbtable'; $tableattributes = "class='$class'$mytabattr"; if($caption)$caption = "<caption>$caption</caption>"; $cellattributes = "$h$w"; $celldivattributes = $htmlpx? " style='padding:$pad $pad;'":''; $_tmpl_item = $ThumbList['_tmpl']['cellwrap']; } else {$_tmpl_item = $ThumbList['_tmpl']['inlinewrap'];} $output = $notfound=''; $items = array();# cells or thumbs foreach($filelist as $file=>$arr) { $filepath = "$uploaddir/$file"; $info = (isset($arr['getimagesize']))? $arr['getimagesize'] : @getimagesize($filepath); if(!isset($ThumbList['ImTypes'][@$info[2]])) { $c = trim($arr['_c'])>'' ? Keep(" ({$arr['_c']}) ") : ''; if($suffix!='list')$notfound .= "* [[Attach:$pagename/$file | $file$c]]\n"; continue; } $_captionfmt = (@$arr['_c'])? $arr['_c']: $captionfmt; $_titlefmt = (@$arr['_t'])? $arr['_t']: $titlefmt; $picurl = PUE("$uploadurl$file"); $stat = (isset($arr['stat']))? $arr['stat'] : stat($filepath); $replArr = array( "??" => "?", "?G" => $ThumbGalNum, "?P" => $pagename, "?p" => preg_replace("/^.*\\./", '', $pagename), "?f" => $file, "?w" => $info[0], "?h" => $info[1], "?r" => round($info[0]/$info[1],2), "?a" => $info[0]*$info[1], "?b" => $stat['size'],"?k" => round($stat['size']/1024), "?t" => strftime($TimeFmt, $stat['mtime']), "?1" => $_titlefmt, "?2" => htmlspecialchars($_titlefmt, ENT_QUOTES), "?3" => $_captionfmt, "?4" => htmlspecialchars($_captionfmt, ENT_QUOTES), ); if($enableexif)$replArr += $ThumbList['fEXIF']($filepath); ## when inside an ImageTemplate, set pagevars for 1 pic and exit if(@$opt['onlysetpagevars']){ThumbSetPageVars($replArr); return;} if(($thumbcols && $info[0]>$info[1] && ! @$Height) || @$Width) # w > h { $imgw = $Px; $imgh = round($Px * $info[1] / $info[0]);} else { $imgh = $Px; $imgw = round($Px * $info[0] / $info[1]);} if($imgh>=$info[1])# picture not bigger than thumb, display it { if($imgh>=$info[1])list($imgw, $imgh)= $info; $thumburl = $picurl; } else { $thumbprefix = "th$imgh---".substr($mybgcolor, 1). "--"; $thumbpath = "$uploaddir/$thumbprefix$file.$thumbext"; if(file_exists($thumbpath) && filemtime($thumbpath)>=$stat['mtime']) $thumburl = PUE("$uploadurl$thumbprefix$file.$thumbext"); elseif(!$ThumbList['EnableThumbs'])$thumburl=''; else { $thumburl = PUE( FmtPageName("\$PageUrl?action=createthumb&imcl=$imcl&upname=", $pagename) ."$thumbprefix$file.$thumbext"); $opt['supercache'] = $supercache = 0; touch("$uploaddir/.$thumbprefix$file.$thumbext.lock"); NoCache(); } } $Mx = max($imgh, $imgw); $widthheight = $htmlpx ? "width='$imgw' height='$imgh'" : ''; $ud = ($pagename == $currentpage)? '':"&updir=$pagename"; $linkurl = $picurl; if(preg_match("/^{$GroupPattern}[\\.\\/]{$NamePattern}$/", $linkorig)) $linkurl = PUE(FmtPageName("\$PageUrl", $linkorig)); elseif($linkorig==2)$linkurl = PUE(FmtPageName("\$PageUrl", $pagename)); elseif($usetpl)$linkurl = PUE(FmtPageName("\$PageUrl?action=imgtpl&G=$ThumbGalNumGet$ud&upname=$file", $currentpage)); $replArr+=array("?U" => $picurl,"?u" => $thumburl, '?L' => $linkurl, '?n'=>" | ", '?N'=>" | "); $item = $thumburl? sprintf($ThumbList['_tmpl']['imgwrap'], strtr($_titlefmt, $replArr), $widthheight): $_titlefmt; $replArr['?n'] = $replArr['?N'] = '<br/>'; if($linkorig!=-1 && ($linkorig>0 || $thumburl != $picurl || $usetpl )) { $rel = ($linkrel>'')? " rel='$linkrel'" : ''; if($linktarget>'') $rel.= " target='$linktarget'"; $item = sprintf($ThumbList['_tmpl']['awrap'], $item, $rel); } if($_captionfmt>'')$_captionfmt = sprintf($ThumbList['_tmpl']['captionwrap'], $_captionfmt); $_celldivattributes = sprintf(@$celldivattributes, round(($Mx-$imgh)/2)+2, round(($Mx-$imgw)/2)+2); $item = sprintf($_tmpl_item, $item, $_captionfmt, @$cellattributes, $_celldivattributes); $items[] = strtr( $item, $replArr); $trail.="$file\n"; if($usetpl && $stat['mtime']>=$trailstamp && @$opt['order']!='random')$trailcache = 1; } if($thumbcols>0) { $output = ''; for($i=0; $i<count($items); $i+=$thumbcols) { $output .= sprintf($ThumbList['_tmpl']['rowwrap'], implode('', array_slice($items, $i, $thumbcols))); } $output = sprintf($ThumbList['_tmpl']['tablewrap'], $tableattributes, $caption, $output); } else $output = sprintf($ThumbList['_tmpl']['inlinewrapall'], implode('', $items)); $output = ($ThumbGalNumBase==1? "<!-- TL2-{$RecipeInfo['ThumbList']['Version']} -->":'') . trim($output); if($ThumbList['AttachLinks'] && $quiet<2 && strlen($notfound)) $output .= $notfound; if(!@$_POST['preview']) { if($supercache)ThumbSetCache($currentpage, $pagename, $ThumbGalNum, MarkupRestore($output)); if($usetpl>0 && $trailcache)ThumbSetCache($currentpage, $pagename, $ThumbGalNum, $trail, 1); } if($tlmode>=0) return ThumbReturn($output); } function ThumbReturn($x,$err=0) { global $ThumbList_ShowErrors; if($ThumbList_ShowErrors==0 && $err==1) return; $a=$b=''; if($err){$a='<pre><b>ThumbList warning: </b>';$b='</pre>';} if(strpos($x,'<')!==false)$x = preg_replace('/<[^<]*?>/e',"Keep(PSS('$0'))",$x); return "<:block>$a$x$b"; } # returns a list of all potential files from the upload directory function ThumbGetFileList($uploaddir, $opt) { global $ThumbList; if (@$opt['skip']) $skipmatch=ThumbFilePattern($opt['skip'], 'i'); if (@$opt['name']) $pattern = ThumbFilePattern($opt['name'], 'i'); $filelist = array(); $dirp = @opendir($uploaddir); if($dirp) { while (($file=readdir($dirp)) !== false) { if ($file{0} == '.') continue; if (!preg_match("/{$ThumbList['ImTypesRegExp']}$/i", $file)) continue; if (preg_match("/^th\\d+---/", $file)) { continue; } if (@$skipmatch && preg_match(@$skipmatch, $file)) continue; if (@$pattern && !preg_match($pattern, $file)) continue; $filelist[$file] = $ThumbList['fGetFileStat']($uploaddir, $file, $opt); } closedir($dirp); } return $filelist; } function ThumbGetFileStat($uploaddir, $file, $opt) { global $ThumbList; $ext = preg_replace("/^.*\\.([^\\.]*)$/", '$1', $file); $r = array('name'=>$file, 'ext'=>$ext); foreach( (array)$ThumbList['stat_dirlist'] as $k=>$v ) if(preg_match("/^-?$k$/", @$opt['order']) && function_exists($v) ) $r[$v]=$v("$uploaddir/$file"); return $r; } function ThumbOrderFileList($filelist, $opt, $uploaddir) { global $ThumbList; preg_match('/^(-)?(\\w*)$/', @$opt['order'], $m); @list(, $rev, $order) = (array)@$m; if($order!='none') { if(! @$ThumbList['OrderFunctions'][$order]) $order='name'; usort($filelist, create_function('$a,$b', $ThumbList['OrderFunctions'][$order]) ); $f2=array();foreach($filelist as $k=>$a)$f2[$a['name']]=$a; $filelist=$f2; } return ($rev=='-')? array_reverse($filelist, 1) : $filelist; } function ThumbFilePattern($x, $mod=''){return '/^'.str_replace(array("\\*","\\?","\\|"),array(".*",".","|"),preg_quote($x)).'$/'.$mod;} function ThumbCacheName($currentpage, $uploadpage, $n, $trail=0, $delete=0) { global $UploadDir, $UploadPrefixFmt; $t = $trail? '-trail' : ''; $f = FmtPageName("$UploadDir$UploadPrefixFmt/.thumblist$t.$currentpage.$n.cache", $uploadpage); if(!$delete) return $f; if(file_exists($f)) @unlink($f); } function ThumbGetCache($currentpage, $uploadpage, $n, $trail=0) { global $PCache, $MessagesFmt; $ptime = $PCache[$currentpage]['time']; $t = ($trail)? '-trail' : ''; $cachefile = ThumbCacheName($currentpage, $uploadpage, $n, $trail); if(file_exists($cachefile) && filemtime($cachefile) >= $ptime) { $MessagesFmt[] = "Getting cache for $currentpage, gallery$t $n<br />\n"; if($trail==2) return filemtime($cachefile); if($handle = @fopen($cachefile, "r")) { $contents = @fread($handle, filesize($cachefile)); fclose($handle); } return @$contents; } } function ThumbSetCache($currentpage, $uploadpage, $n, $html, $trail=0) { global $UploadDir, $UploadPrefixFmt, $MessagesFmt; $t = ($trail)? '-trail' : ''; $MessagesFmt[] = "Caching gallery$t $n for $currentpage<br />\n"; $cachefile = ThumbCacheName($currentpage, $uploadpage, $n, $trail); if ($handle = @fopen($cachefile, 'w+')) { @fwrite($handle, $html); fclose($handle); } } function ThumbExif($filepath) { $e = $exif = array(); global $TimeFmt; $exif = @exif_read_data($filepath, 'EXIF', 1); $e['?M'] = @$exif['IFD0']['Make']; $e['?m'] = @$exif['IFD0']['Model']; $e['?W'] = IsEnabled($exif['COMPUTED']['Width'], @$exif['EXIF']['ExifImageWidth']); $e['?H'] = IsEnabled($exif['COMPUTED']['Height'], @$exif['EXIF']['ExifImageHeight']); $t = preg_replace('/^(\\d{4}):(\\d\\d):(\\d\\d.*)/', '$1-$2-$3', @$exif['EXIF']['DateTimeOriginal']); $e['?T'] = @$t? strftime($TimeFmt,strtotime($t)):''; $e['?E'] = @$exif['EXIF']['ExposureTime']; $e['?F'] = @$exif['EXIF']['FocalLength']; $e['?A'] = @$exif['COMPUTED']['ApertureFNumber']; $e['?I'] = @$exif['EXIF']['ISOSpeedRatings']; $e['?C'] = trim(@$exif['COMMENT']['0'].' '.@$exif['COMPUTED']['UserComment']); return $e; }