require_plugin('smd_lib'); // MLP support global $smd_gallLang; $smd_gallStr = array( 'navfirst' => 'First', 'navlast' => 'Last', 'navprev' => '«', 'navnext' => '»', ); $smd_gallLang = new smd_MLP('smd_gallery', 'smd_gall', $smd_gallStr); function smd_gallery($atts, $thing='') { global $pretext, $thisarticle, $img_dir, $dateformat, $smd_gallLang, $l10n_language; // Plugin options extract(lAtts(array( 'columns' => '', 'delim' => ',', 'paramdelim' => ':', 'collatedelim' => ',', 'strictfields' => '0', 'form' => '', 'countform' => '', 'countpos' => 'above', 'id' => '', 'category' => '', 'aspect' => '', 'author' => '', 'dimensions' => '', 'extension' => '', 'directory' => '', 'match' => '', 'sublevel' => '0', 'escape' => 'alt, title, caption', 'sort' => '', 'offset' => '0', 'limit' => '0', 'maxlimit' => '99999', 'thumblimit' => '99999', 'thumboffset' => '0', 'thumb' => '0:1', 'thumbsize' => '', 'imgsize' => '', 'onchange' => 'category', 'onchangewraptag' => '', 'onchangeclass' => '', 'objectform' => '', 'grouptag' => '', 'groupclass' => '', 'text' => '', 'format' => $dateformat, 'gmt' => '', 'lang' => '', 'collate' => '', 'combo' => '', 'paging' => '0', 'pageform' => '', 'pagepos' => 'below', 'navwraptag' => 'ul', 'navbreak' => 'li', 'navclass' => 'smd_gallery_nav', 'emptyclass' => 'empty', 'galleryid' => '?4:6', 'wraptag' => '', 'html_id' => '', 'break' => '', 'class' => '', 'debug' => '0', ), $atts)); // Category relies on whether id has been specified or not. // lAtts() won't let us handle this logic so it has to be done manually $attemptMatch = (empty($category) && empty($id)) ? false : true; $category = isset($category) ? doSlash($category) : (($id=='') ? $pretext['c']: ''); $sort = ($sort) ? $sort : ( ($id) ? 'id' : 'category' ); // ** LOOKUP TABLES // $fieldMap holds database column as key, and replacement identifier as value. // Additional cols copied to $extraMap for iteration while creating replacements. // Use array_search to find if value exists and return correct key for use in db calls/array refs. $fieldMap = array(); $extraMap = array(); $coreCols = array("name", "id", "alt", "caption", "category", "author", "date", "ext", "w:width", "h:height", "thumb_w:thumb_width", "thumb_h:thumb_height", "thumbnail:hasthumb"); $mlpFields = array("alt", "caption"); // Manually create the MLP column names, since using getRows() later does not. Category title also has the same treatment $thislang = (isset($l10n_language['long'])) ? $l10n_language['long'] : LANG; $dflt_tbl = PFX."txp_image"; $columns = do_list($columns); foreach (array_merge($coreCols, $columns) as $colinfo) { $colbit = do_list($colinfo, ":"); $coltbl = do_list($colbit[0], "."); if ($colbit[0] == '') continue; if (count($coltbl) > 1) { $tbl = $coltbl[0]; $colname = $coltbl[1]; } else { $tbl = $dflt_tbl; $colname = $coltbl[0]; } $colid = (count($colbit) > 1) ? $colbit[1] : $colname; $fieldMap[(($tbl)?$tbl.'.':'').( (isset($l10n_language['long']) && in_array($colname, $mlpFields)) ? _l10n_make_field_name($colname, $thislang). ' AS '.$colname : $colname )] = $colid; if (!in_array($colinfo, $coreCols)) { $extraMap[$colname] = $colid; } } $fieldMap = array_unique($fieldMap); // Handle forms and set a default tag if none specified $thing = (empty($form)) ? $thing : fetch_form($form); $thing = (empty($thing)) ? '' : $thing; $objectform = (empty($objectform)) ? '' : fetch_form($objectform); // Counting $countPosAllowed = array("above", "below"); $countposns = array(); $counting = 0; if ($countform) { $counting = 1; $countform = do_list($countform, $delim); $countpos = str_replace('smd_', '', $countpos); // For convenience $countpos = do_list($countpos, $delim); foreach ($countpos as $countitem) { $countposns[] = (in_array($countitem, $countPosAllowed)) ? $countitem : $countPosAllowed[0]; } } // Paging init $pagePosAllowed = array("below", "above"); $pageout = array(); if ($pageform) { $paging = 1; $pageform = fetch_form($pageform); $pagepos = str_replace('smd_', '', $pagepos); $pagepos = do_list($pagepos, $delim); foreach ($pagepos as $pageitem) { $pageout[] = (in_array($pageitem, $pagePosAllowed)) ? $pageitem : $pagePosAllowed[0]; } } // onchange verification $onchange = do_list($onchange, $delim); $onchange = ($onchange[0] == "") ? array() : $onchange; $resetOpts = array(); foreach ($onchange as $resetOpt) { $resetOpts[$resetOpt] = ""; } // Escaping $spc = ($strictfields) ? 0 : 1; $escapes = do_list($escape, $delim); foreach ($escapes as $idx => $val) { if ($val == '') { unset($escapes[$idx]); } } // The gallery identifier is used for keeping track of next/prev thumbnail page links $gallID = ''; if ($galleryid == '' || substr($galleryid,0,1) == "?") { // Generate a (fairly likely) unique ID for this gallery instance $gallTmp = md5($category.$id.$directory.$match.$sublevel.$sort.$limit.$maxlimit); list($gallLen, $gallSkip) = explode(":", substr($galleryid,1)); $gallLen = (empty($gallLen)) ? "4" : $gallLen; $gallSkip = (empty($gallSkip)) ? "1" : $gallSkip; for ($idx = 0, $cnt = 0; $cnt < $gallLen; $cnt++, $idx = (($idx+$gallSkip) % strlen($gallTmp))) { $gallID .= $gallTmp[$idx]; } } else { $gallID = $galleryid; } $gallID = "smd_glry_".$gallID; // Avoid (already incredibly unlikely) namespace clashes // Set up the variables from the thumb option. // Don't use paramdelim here or the default option breaks $thumbOpts = do_list($thumb, ":"); if (count($thumbOpts) == 1) { $fullmod = ($thumbOpts[0] == 1) ? "t" : ""; $thumbmod = "t"; } else { $fullmod = ($thumbOpts[0] == 1) ? "t" : ""; $thumbmod = ($thumbOpts[1] == 1) ? "t" : ""; } // The manner of obtaining files differs if using directory vs category/id $rs = array(); if ($directory) { $rs = smd_doDirectory($directory, 0, $sublevel, $match, $delim, $spc); list($allImages, $numPages, $thumPage, $offset) = smd_getPage($rs, $gallID, $limit, $offset, $paging); $dirlimit = ($limit==0) ? $maxlimit : $limit; $postOrder = array(); $fixedOrder = 0; $randsort = false; } else { // Process categories/IDs and make up the crux of the where clause. // Clause order = IDs OR cats AND !cats AND !IDs $clause[] = '1=1'; $clauseOR = array(); // Surround each entry in the ID list with quotes and make an SQL "in" list $subinfo = ($sublevel) ? "image:".$sublevel : ''; list($idinc, $idexc) = smd_doList($id, true, '', true, $delim, $spc); list($catinc, $catexc) = smd_doList($category, false, $subinfo, true, $delim, $spc); if ($idinc) { $clauseOR[] = PFX.'txp_image.id IN ('.implode(",", $idinc).')'; } if ($catinc) { $clauseOR[] = PFX.'txp_image.category IN ('.implode(",", $catinc).')'; } if (!empty($clauseOR)) { $clause[] = ' ('.implode(" OR ", $clauseOR).') '; } $clause = implode(" AND ", $clause); $clause .= ($catexc) ? ' AND '.PFX.'txp_image.category NOT IN ('.implode(",", $catexc).')' : ''; $clause .= ($idexc) ? ' AND '.PFX.'txp_image.id NOT IN ('.implode(",", $idexc).')' : ''; // If a category/id option was chosen and they matched nothing, use a bogus category that should not exist. // This ensures that the plugin does the expected thing of matching nothing in the event it finds nothing. if ($clause == "1=1" && $attemptMatch) { $clause = PFX.'txp_image.category = "smd_' .mt_rand(). '"'; } $clause = '('.str_replace('SMD_EMPTY', '', $clause).')'; if ($debug > 1) { echo "++ INCLUDED/EXCLUDED IDs AND CATs ++"; if ($idinc) dmp($idinc); if ($idexc) dmp($idexc); if ($catinc) dmp($catinc); if ($catexc) dmp($catexc); } // Filter by aspect ratio if ($aspect) { $aspects = do_list($aspect, $delim); // Compare fullsize or thumbnail aspect ratios $fldmod = ($fullmod) == 't' ? 'thumb_' : ''; $wfld = PFX.'txp_image.'.$fldmod.'w'; $hfld = PFX.'txp_image.'.$fldmod.'h'; $clauseOR = array(); foreach ($aspects as $ratio) { switch($ratio) { case 'portrait': $clauseOR[] = $hfld. ' > '. $wfld; break; case 'landscape': $clauseOR[] = $wfld. ' > '. $hfld; break; case 'square': $clauseOR[] = $hfld. ' = '. $wfld; break; } } if (!empty($clauseOR)) { $clause .= ' AND '.$wfld.' > 0 AND '.$hfld.' > 0 AND ('.implode(" OR ", $clauseOR).') '; } } // Filter by author if ($author) { $authors = do_list($author, $delim); $clause .= " AND " . PFX."txp_image.author IN ('".implode("','", $authors)."')"; } // Filter by extension if ($extension) { $extensions = do_list($extension, $delim); foreach ($extensions as $idx => $ext) { $extensions[$idx] = ".".$ext; } $clause .= " AND " . PFX."txp_image.ext IN ('".implode("','", $extensions)."')"; } // Filter by dimensions if ($dimensions) { $dimAllow = array('=', '>', '<', '>=', '<='); $dims = do_list($dimensions, $delim); // Compare fullsize or thumbnail aspect ratios $fldmod = ($fullmod) == 't' ? 'thumb_' : ''; $wfld = PFX.'txp_image.'.$fldmod.'w'; $hfld = PFX.'txp_image.'.$fldmod.'h'; $wdim = $dims[0]; $hdim = (isset($dims[1])) ? $dims[1] : ''; $wdimval = preg_replace('/[^0-9]/', '', $wdim); $hdimval = preg_replace('/[^0-9]/', '', $hdim); $wdimop = preg_replace('/[0-9]/', '', $wdim); $wdimop = in_array($wdimop, $dimAllow) ? $wdimop : '='; $hdimop = preg_replace('/[0-9]/', '', $hdim); $hdimop = in_array($hdimop, $dimAllow) ? $hdimop : '='; $clause .= (($wdim) ? ' AND ' . $wfld . $wdimop . $wdimval : '') . (($hdim) ? ' AND ' . $hfld . $hdimop . $hdimval : ''); } // Convert the sort into a valid sorting hierarchy. // Note that random is a special case and the following rules apply: // 1) Anything appearing before random is passed to the database query for ordering // 2) As soon as random is encountered, the rest of the sort string is ignored. // The resultset will be sorted randomly instead // 3) If random appears first in the list, the data is retrieved randomly then the // remaining options sort the resultset $clauseSort = array(); $postOrder = array(); $rule = "sql"; $postPrefix = "SORT_"; $fixedOrder = $randsort = false; $sort = do_list($sort, $delim); for ($idx = 0; $idx < count($sort); $idx++) { $sort_dir = explode(' ', $sort[$idx]); $direction = $colRef = ''; if (count($sort_dir) <= 1) { $sort_dir[1] = "asc"; } if ($rule == "sql") { $direction = ($sort_dir[1] == "desc") ? ' desc' : ' asc'; } else { $direction = ($sort_dir[1] == "desc") ? $postPrefix.'DESC' : $postPrefix.'ASC'; } switch ($sort_dir[0]) { case 'random': $rule = "post"; if ($idx == 0) { $clauseSort[] = 'rand()'; } else { $randsort = true; } break; case 'fixed': // 'fixed' only works on ids or categories $fixedOrder = ($id == '' && $category == '') ? false : true; break; default: $colRef = array_search($sort_dir[0], $fieldMap); $colName = $fieldMap[$colRef]; break; } if ($rule == "sql") { if ($colRef != '') { $clauseSort[] = $colRef.$direction; } } else { if (!$randsort) { if ($colRef != '') { $postOrder[] = array("col" => $colName, "sort" => $direction); } } } } if (count($clauseSort) > 0) { $clause .= ' ORDER BY ' . implode(",",$clauseSort); } if ($debug > 0) { echo "++ WHERE CLAUSE ++"; dmp($clause); } // The database fields required $fields = implode(",", array_keys($fieldMap)); $cTitle = (isset($l10n_language['long'])) ? _l10n_make_field_name('title', $thislang) : 'title'; $rs = getRows(" SELECT DISTINCT $fields, ".PFX."txp_category.".$cTitle." AS category_title FROM ".PFX."txp_image LEFT JOIN ".PFX."txp_category ON ".PFX."txp_image.category = ".PFX."txp_category.name WHERE $clause LIMIT 0, $maxlimit ", $debug); list($allImages, $numPages, $thumPage, $offset) = smd_getPage($rs, $gallID, $limit, $offset, $paging); } // Is post-ordering required? Do it if ($randsort) { shuffle($rs); } else if (count($postOrder) > 0) { // Translate the rows into columns that can be sorted foreach($rs as $key => $row) { foreach ($row as $identifier => $item) { $varname = "col_".$identifier; ${$varname}[$key] = $item; } } // Make up an array_multisort arg list and execute it. // The necessary evil() is because we don't know how many cols there will be in the array for ($idx = 0; $idx < count($postOrder); $idx++) { $sortargs[] = '$col_'.$postOrder[$idx]['col']; $sortargs[] = $postOrder[$idx]['sort']; } $sortit = 'array_multisort('.implode(", ",$sortargs).', $rs);'; eval($sortit); } // Is fixed-order output desired? If so, re-order the $rs if ($fixedOrder) { $orderedRS = Array(); $ignoreList = Array(); $remainingRS = Array(); // Suck out the fixed items first. IDs then categories for ($idx = 0; $idx < count($idinc); $idx++) { foreach($rs as $row) { if ($id && doQuote($row['id']) == $idinc[$idx]) { $orderedRS[] = $row; $ignoreList[] = $row['id']; break; } } } for ($idx = 0; $idx < count($catinc); $idx++) { foreach($rs as $row) { if ($category && doQuote($row['category']) == $catinc[$idx]) { $orderedRS[] = $row; $ignoreList[] = $row['id']; } } } // Tack on the remaining rows if ($rs) { foreach($rs as $row) { if (!in_array($row['id'], $ignoreList)) { $remainingRS[] = $row; } } } $rs = array_merge($orderedRS, $remainingRS); } // Grab the portion of the record set actually required to iterate over if ($rs) { $rs = array_slice($rs, $offset, (($directory) ? $dirlimit : (($limit==0) ? $maxlimit : $limit))); } // Prepare fixed thumbsizes $thumbWidth = $thumbHeight = ''; $thumbWUnits = $thumbHUnits = ''; if ($thumbsize) { $thumbSizes = do_list($thumbsize, $delim); $units = preg_replace('/[0-9]/', '', $thumbSizes[0]); if (count($thumbSizes) == 1) { $thumbWidth = $thumbHeight = preg_replace('/[^0-9]/', '', $thumbSizes[0]); $thumbWUnits = $thumbHUnits = ($units == '') ? $thumbWUnits : $units; } else { $thumbWidth = preg_replace('/[^0-9]/', '', $thumbSizes[0]); $thumbHeight = preg_replace('/[^0-9]/', '', $thumbSizes[1]); $thumbWUnits = ($units == '' && $thumbWidth != '') ? $thumbWUnits : $units; $units = preg_replace('/[0-9]/', '', $thumbSizes[1]); $thumbHUnits = ($units == '' && $thumbHeight != '') ? $thumbHUnits : $units; } } // Prepare fixed image sizes $imageWidth = $imageHeight = ''; $imageWUnits = $imageHUnits = ''; if ($imgsize) { $imageSizes = do_list($imgsize, $delim); $units = preg_replace('/[0-9]/', '', $imageSizes[0]); if (count($imageSizes) == 1) { $imageWidth = $imageHeight = preg_replace('/[^0-9]/', '', $imageSizes[0]); $imageWUnits = $imageHUnits = ($units == '') ? $imageWUnits : $units; } else { $imageWidth = preg_replace('/[^0-9]/', '', $imageSizes[0]); $imageHeight = preg_replace('/[^0-9]/', '', $imageSizes[1]); $imageWUnits = ($units == '' && $imageWidth != '') ? $imageWUnits : $units; $units = preg_replace('/[0-9]/', '', $imageSizes[1]); $imageHUnits = ($units == '' && $imageHeight != '') ? $imageHUnits : $units; } } // Collation defers parsing the form for each returned item. // Instead it outputs the data as a list at the end (items may be individually quoted or extracted if required) //TODO : Add ALWAYS switch as a shortcut to specify that all matching items (regardless of #1, #2, #3 etc) are to be quoted if ($collate) { $dblQuote = $sglQuote = array('SMDNONE'); $collateOpts = do_list($collate, $delim); foreach ($collateOpts as $option) { $indexes = do_list($option, $paramdelim); $colType = array_shift($indexes); // Supplying 'quote' on its own will empty the relevant array, implying "ALL" fields are to be quoted switch ($colType) { case "sglquote": $sglQuote = $indexes; break; case "dblquote": case "quote": $dblQuote = $indexes; break; } } } // Combos are user-defined combinations of replacement modifiers (e.g. idext: {id}{ext}, ... $combos = array(); if ($combo) { $combo = do_list($combo, $delim); foreach ($combo as $newDef) { list($defParts, $unwanted) = smd_doList($newDef, false, '', false, $paramdelim, $spc); $defName = "{".array_shift($defParts)."}"; $combos[$defName] = $defParts[0]; } } if ($debug > 1) { echo "++ COMBOs ++"; dmp($combos); } // Construct the output $thumbout = array(); $groupout = array(); $navout = array(); $out = array(); $collations = array(); $chIdentifier = "onchange"; if ($debug > 2) { echo "++ RECORD SET ++"; dmp($rs); } if ($debug > 3) { echo "++ AVAILABLE '?' VARS ++"; if ($pretext) dmp($pretext); if ($thisarticle) dmp($thisarticle); } if($rs) { $idx = 0; $ctr = 1; $thumbIdx = 0; $thumbCtr = 1; $numImages = count($rs); $repagements = array(); // Set up the paging features if required if (($limit > 0) && $paging) { $next = ($numPages > 1 && $thumPage != $numPages); $prev = ($numPages > 1 && $thumPage > 1); $prevPage = smd_addQSVar($pretext['request_uri'], $gallID, $thumPage-1); $nextPage = smd_addQSVar($pretext['request_uri'], $gallID, $thumPage+1); $thisPage = smd_addQSVar($pretext['request_uri'], $gallID, $thumPage); $firstPage = smd_addQSVar($pretext['request_uri'], $gallID, 1); $lastPage = smd_addQSVar($pretext['request_uri'], $gallID, $numPages); // Labels can be specified in the replacement tag after a paramdelim. // 'earlier' and 'later' don't have labels. Anything specified after paramdelim is the max number of pages to show; empty = all pages $label = array( '{navfirst}' => $smd_gallLang->gTxt('navfirst'), '{navprev}' => $smd_gallLang->gTxt('navprev'), '{navearlier}' => '', '{navthis}' => $thumPage, '{navthisurl}' => $thumPage, '{navlater}' => '', '{navnext}' => $smd_gallLang->gTxt('navnext'), '{navlast}' => $smd_gallLang->gTxt('navlast'), ); $labelRE = '/\{(nav[a-z]+)'.$paramdelim.'(.+?)\}/'; $numLabels = preg_match_all($labelRE, $pageform, $labels); for ($labelCtr = 0; $labelCtr < $numLabels; $labelCtr++) { $fieldname = '{'.$labels[1][$labelCtr].'}'; $label[$fieldname] = $labels[2][$labelCtr]; $pageform = str_replace($labels[0][$labelCtr], '{'.$labels[1][$labelCtr].'}', $pageform); } if ($debug > 1) { echo "++ PAGING LABELS ++"; dmp($label); } // Generate 'earlier' and 'later' lists $numEarlier = intval($label['{navearlier}']); $numLater = intval($label['{navlater}']); $numEarlier = ($numEarlier && ($thumPage-$numEarlier > 1)) ? $numEarlier : $thumPage-1; $numLater = ($numLater && ($thumPage+$numLater < $numPages)) ? $numLater : $numPages-$thumPage; $navEarlier = $navLater = array(); for ($cod = $thumPage-$numEarlier; $cod < $thumPage; $cod++) { $navEarlier[] = ''.$cod.''; } for ($cod = $thumPage+1; $cod <= $thumPage+$numLater; $cod++) { $navLater[] = ''.$cod.''; } $navEarlier = doWrap($navEarlier, '', $navbreak, ''); $navLater = doWrap($navLater, '', $navbreak, ''); // Make up the repagements array for pageform $repagements = array( '{navfirst}' => (($prev) ? doTag(''.$label['{navfirst}'].'', $navbreak) : doTag($label['{navfirst}'], $navbreak, $emptyclass)), '{navprev}' => (($prev) ? doTag(''.$label['{navprev}'].'', $navbreak) : doTag($label['{navprev}'], $navbreak, $emptyclass)), '{navearlier}' => $navEarlier, '{navthis}' => doTag($label['{navthis}'], $navbreak, 'current '.$emptyclass), '{navthisurl}' => doTag(''.$label['{navthisurl}'].'', $navbreak, 'current'), '{navlater}' => $navLater, '{navnext}' => (($next) ? doTag(''.$label['{navnext}'].'', $navbreak) : doTag($label['{navnext}'], $navbreak, $emptyclass)), '{navlast}' => (($next) ? doTag(''.$label['{navlast}'].'', $navbreak) : doTag($label['{navlast}'], $navbreak, $emptyclass)), '{navthispageurl}' => $thisPage, '{navnextpageurl}' => (($next) ? $nextPage : ''), '{navprevpageurl}' => (($prev) ? $prevPage : ''), '{navfirstpageurl}' => $firstPage, '{navlastpageurl}' => $lastPage, '{totalimages}' => $numImages, '{totalpages}' => $numPages, '{maximages}' => $allImages, ); // Perform escaping here, just prior to output if ($escapes) { foreach ($repagements as $defName => $defVal) { if (in_array(trim($defName, "{}"), $escapes)) { $repagements[$defName] = htmlspecialchars($defVal, ENT_QUOTES); } } } // Perform the substitutions $navout[] = parse(strtr($pageform, $repagements)); } // For every image in the gallery... foreach($rs as $key => $row) { if ($directory) { $urlPath = $row['path'].'/'; } else { $urlPath = hu.$img_dir.'/'; } $theThumb = $urlPath . $row['id'] . $thumbmod . $row['ext']; $fullSize = $urlPath . $row['id'] . $fullmod .$row['ext']; // Do we need to reset the thumb counter this time? foreach ($resetOpts as $resetOpt => $resetVal) { if (strpos($resetOpt, 'smd_every') === 0) { $iter = explode($paramdelim, $resetOpt); $iter = (count($iter) > 1) ? $iter[1] : 0; if ($thumbIdx % $iter == 0) { $thumbIdx = 0; $thumbCtr = 1; } } else if ($row[$resetOpt] != $resetVal) { $thumbIdx = 0; $thumbCtr = 1; break; } } // Override thumbsize / imgsize if required if ($thumbsize) { $theThumbWidth = empty($thumbWidth) ? $row['thumb_w'] : $thumbWidth; $theThumbHeight = empty($thumbHeight) ? $row['thumb_h'] : $thumbHeight; $theThumbWUnits = $thumbWUnits; $theThumbHUnits = $thumbHUnits; } else { $theThumbWidth = $row['thumb_w']; $theThumbHeight = $row['thumb_h']; $theThumbWUnits = $theThumbHUnits = ''; } if ($imgsize) { $theImageWidth = empty($imageWidth) ? $row['w'] : $imageWidth; $theImageHeight = empty($imageHeight) ? $row['h'] : $imageHeight; $theImageWUnits = $imageWUnits; $theImageHUnits = $imageHUnits; } else { $theImageWidth = $row['w']; $theImageHeight = $row['h']; $theImageWUnits = $theImageHUnits = ''; } // Construct the replacement array $replacements = array( '{id}' => $row['id'], '{name}' => $row['name'], '{ext}' => $row['ext'], '{category}' => $row['category'], '{category_title}' => ((isset($row['category_title'])) ? $row['category_title'] : ''), '{author}' => $row['author'], '{hasthumb}' => (isset($row['thumbnail']) ? $row['thumbnail'] : 0), '{url}' => $fullSize, '{thumburl}' => $theThumb, '{imagepath}' => $urlPath, '{imagedef}' => basename($fullSize), '{thumbdef}' => basename($theThumb), '{alt}' => $row['alt'], '{title}' => $row['caption'], '{caption}' => $row['caption'], '{thumbwidth}' => $theThumbWidth, '{thumbheight}' => $theThumbHeight, '{thumbwunits}' => $theThumbWUnits, '{thumbhunits}' => $theThumbHUnits, '{width}' => $theImageWidth, '{height}' => $theImageHeight, '{wunits}' => $theImageWUnits, '{hunits}' => $theImageHUnits, '{date}' => (($format) ? safe_strftime($format, strtotime($row['date']), $gmt, $lang) : $row['date']), '{galleryid}' => $gallID, '{index}' => $idx, '{counter}' => $ctr, '{thumbindex}' => $thumbIdx, '{thumbcounter}' => $thumbCtr, '{totalimages}' => $numImages, '{maximages}' => $allImages, ); // Add any custom columns foreach ($extraMap as $eCol => $eVal) { $replacements['{'.$eVal.'}'] = $row[$eCol]; } // Append any changed items that are required $endtag = false; foreach ($resetOpts as $resetOpt => $resetVal) { if (strpos($resetOpt, 'smd_every') === 0) { $iter = explode($paramdelim, $resetOpt); $iter = (count($iter) > 1) ? $iter[1] : 0; if ($thumbCtr % $iter === 0 || $ctr == $numImages) { $endtag = true; } } else { $replacements['{'.$chIdentifier.$paramdelim.$resetOpt.'}'] = ($thumbIdx == 0) ? doTag($row[$resetOpt], $onchangewraptag, $onchangeclass) : ''; // Do a sneaky (yuk) lookahead if (isset($rs[$key+1])) { if($rs[$key+1][$resetOpt] != $row[$resetOpt]) { $endtag = true; } } else { $endtag = true; // Last image } } } $replacements['{grouptagend}'] = ($grouptag && $endtag) ? '' : ''; $replacements['{grouptagstart}'] = ($grouptag && $thumbIdx == 0) ? '<' . $grouptag . (($groupclass) ? ' class="'.$groupclass.'"' : '') . '>' : ''; // Append any combos foreach ($combos as $defName => $newDef) { if (!array_key_exists($defName, $replacements)) { $replacements[$defName] = strtr($newDef, $replacements); } } // Solos are items in the output form that require details from a specific row. Useful only in collation // mode, they are added to the replacements array on an as-needed basis to save space/time $soloRE = '/\{([a-z0-9]+)#'.$ctr.'\}/'; $numSolos = preg_match_all($soloRE, $thing, $solos); for ($soloCtr = 0; $soloCtr < $numSolos; $soloCtr++) { $fieldname = '{'.$solos[1][$soloCtr].'#'.$ctr.'}'; $grabfield = '{'.$solos[1][$soloCtr].'}'; $replacements[$fieldname] = $replacements[$grabfield]; } // Perform escaping on the replacements. // Note the repagements have already been escaped so when/if they are combined with the replacements, // the escaping is not done twice if ($escapes) { foreach ($replacements as $defName => $defVal) { if (in_array(trim($defName, "{}"), $escapes)) { $replacements[$defName] = htmlspecialchars($defVal, ENT_QUOTES); } } } // Add the navigation items if they're defined if (count($repagements) > 0) { $replacements = array_merge($repagements, $replacements); } // Is a thumb/text object required this time? $object = ''; if ($thumbIdx >= $thumboffset && $thumbIdx < $thumboffset+$thumblimit) { $object = ($objectform) ? parse(strtr($objectform, $replacements)) : (($text) ? $text : ''.$row['alt'].''); } $replacements['{object}'] = $object; if ($debug > 0) { echo "++ REPLACEMENTS : IMAGE ".$ctr." ++"; dmp($replacements); } // Check if countform is to be called $countpre = $countpost = array(); if ($counting) { foreach ($countform as $countlist) { $posover = array(); $countlist = strtr($countlist, $replacements); // Replace any {} vars with their real values $countlist = do_list($countlist, $paramdelim); if ($dpos=array_search('smd_above', $countlist)) { $posover[] = "above"; unset($countlist[$dpos]); } if ($dpos=array_search('smd_below', $countlist)) { $posover[] = "below"; unset($countlist[$dpos]); } $countlist = array_merge($countlist); // re-index $posover = (empty($posover)) ? $countposns : $posover; $divby = false; if ($countlist[0] == 'smd_every') { $divby = true; array_shift($countlist); } $numforms = count($countlist); $callform = fetch_form($countlist[$numforms-1]); unset($countlist[$numforms-1]); $orlogic = $andlogic = array(); foreach ($countlist as $custcount) { $showval = (strpos($custcount, "!") === 0) ? false : true;// Negative logic required $custcount = str_replace('!', '', $custcount); if ($showval) { $orlogic[] = empty($custcount) || (($divby) ? (($ctr % $custcount === 0) ? true : false) : (($custcount == $ctr) ? true : false)); } else { $andlogic[] = ($custcount == $ctr) ? false : true; } } if (in_array('1', $orlogic) && !in_array('0', $andlogic)) { if (in_array("above", $posover)) { $countpre[] = parse(strtr($callform, $replacements)); } if (in_array("below", $posover)) { $countpost[] = parse(strtr($callform, $replacements)); } } } } if ($debug > 0 && ($countpre || $countpost)) { echo "++ COUNT FORM TRIGGERED ++"; if ($countpre) { dmp($countpre); } if ($countpost) { dmp($countpost); } } // In collate mode the form is only parsed at the end: build a collosal multi-dimension array of all items here if ($collate) { foreach ($replacements as $defName => $defVal) { $collations[$defName][] = $defVal; } } else { if ($counting) { $thumbout = array_merge($thumbout, $countpre); } $thumbout[] = parse(strtr($thing, $replacements)); if ($counting) { $thumbout = array_merge($thumbout, $countpost); } } // Keep track of the current values so we know if they change next time foreach ($resetOpts as $resetOpt => $resetVal) { if (strpos($resetOpt, 'smd_every') === false) { $resetOpts[$resetOpt] = $row[$resetOpt]; } else { $resetOpts[$resetOpt] = $thumbCtr; } } $thumbIdx++; $thumbCtr++; $idx++; $ctr++; } if ($collate) { foreach ($collations as $item => $list) { // Quote the lists if required $list = (empty($dblQuote) || in_array($item, $dblQuote)) ? doArray($list, 'smd_doDblQuote') : $list; $list = (empty($sglQuote) || in_array($item, $sglQuote)) ? doArray($list, 'doQuote') : $list; $collations[$item] = implode($collatedelim, $list); } if ($debug > 0) { echo "++ COLLATIONS ++"; dmp($collations); } $thumbout[] = parse(strtr($thing, $collations)); } // Tack on the paging from earlier if it's to go afterwards if (($limit > 0) && $paging) { if ($debug > 0) { echo "++ PAGING REPLACEMENTS ++"; dmp($repagements); } } } // Add the paging to the output if it's to go above the thumbs if (($limit > 0) && $paging) { if (in_array("above", $pageout)) { $out[] = doWrap($navout, $navwraptag, '', $navclass); } } $out[] = doWrap($thumbout, $wraptag, $break, $class, '', '', '', $html_id); if (($limit > 0) && $paging) { if (in_array("below", $pageout)) { $out[] = doWrap($navout, $navwraptag, '', $navclass); } } if ($debug > 2) { echo "++ FINAL OUTPUT ++"; dmp($out); } return join(" ", $out); } // Work out which page this gallery is on and return the relevant info function smd_getPage($rs, $gallID, $limit, $offset, $paging) { $numThums = count($rs) - $offset; if (($limit > 0) && $paging) { $numPages = ($numThums > 0) ? ceil($numThums/$limit) : 1; $thumPage = (!gps($gallID)) ? 1 : gps($gallID); $offset = (($thumPage - 1) * $limit) + $offset; } else { // No paging required $numPages = 1; $thumPage = 1; } return array($numThums, $numPages, $thumPage, $offset); } // Read the given delimited directories and get all files that match. // Go down as many subdir levels as given in the $sub parameter function smd_doDirectory($lst, $lvl=0, $sub=0, $match="", $dlm=",", $spc=1, $ctr=0) { list($dirinc, $direxc) = smd_doList($lst, false, $sub, false, $dlm, $spc); list($matchinc, $matchexc) = smd_doList($match, false, '', false, $dlm, $spc); $matchinc = ".*" .(($matchinc) ? "(" .implode("|",$matchinc).")+.*" : ""); $matchexc = ($matchexc) ? ".*(" .implode("|",$matchexc).")+.*" : "smd_glry_".mt_rand(); $sub = (empty($sub)) ? 0 : $sub; $sub = (strtolower($sub)=="all") ? 99999 : $sub; $fileList = array(); foreach ($dirinc as $dir) { if ($handle = @opendir($dir)) { while (($file = @readdir($handle)) !== false) { $fullpath = $dir.DS.$file; if (preg_match("/".$matchinc."/", $fullpath) && !preg_match("/".$matchexc."/", $fullpath)) { if (is_dir($fullpath)) { if (($file == ".") || ($file== "..") || (in_array($file, $direxc)) || ($lvl >= $sub)) { continue; } else { // Recurse the subdir. Note that the '!' is temporarily added back to each direxc item $tmp = $direxc; // Don't overwrite the original array array_unshift($tmp, $fullpath); $subFiles = smd_doDirectory(implode($dlm."!", $tmp), $lvl+1, $sub, $match, $dlm, $spc, $ctr); $fileList = array_merge($fileList, $subFiles); $ctr += count($subFiles); continue; } } else { $filestat = stat($fullpath); $imgsize = getimagesize($fullpath); $fileList[$ctr]['path'] = $dir; $fileList[$ctr]['name'] = basename($fullpath); $fileList[$ctr]['id'] = preg_replace('/\..+$/', '', $file); $fileList[$ctr]['alt'] = ''; $fileList[$ctr]['caption'] = ''; $parts = explode(DS, $dir); $fileList[$ctr]['category'] = (count($parts) > 1) ? end($parts) : ''; $fileList[$ctr]['author'] = strval($filestat['uid']); $fileList[$ctr]['date'] = strftime("%Y-%m-%d %H:%M:%S", $filestat['ctime']); $parts = explode(".", $file); $fileList[$ctr]['ext'] = (count($parts) > 1) ? ".".end($parts) : ''; $fileList[$ctr]['w'] = (is_array($imgsize)) ? strval($imgsize[0]) : ''; $fileList[$ctr]['h'] = (is_array($imgsize)) ? strval($imgsize[1]) : ''; } $ctr++; } } } if ($handle) { @closedir($handle); } } return $fileList; }