function smd_query($atts, $thing='') { global $pretext, $smd_query_pginfo, $thispage, $thisarticle, $thisimage, $thisfile, $thislink; extract(lAtts(array( 'column' => '', 'table' => '', 'where' => '', 'query' => '', 'form' => '', 'pageform' => '', 'pagevar' => 'pg', 'pagepos' => 'below', 'colsform' => '', 'escape' => '', 'strictfields' => '0', 'preparse' => '0', 'populate' => '', // one of article, image, file, or link 'urlfilter' => '', 'urlreplace' => '', 'defaults' => '', 'delim' => ',', 'paramdelim' => ':', 'silent' => '0', 'mode' => 'auto', // auto chooses one of input (INSERT/UPDATE) or output (QUERY) 'count' => 'up', 'limit' => 0, 'offset' => 0, 'hashsize' => '6:5', 'label' => '', 'labeltag' => '', 'wraptag' => '', 'break' => '', 'class' => '', 'breakclass' => '', 'html_id' => '', 'debug' => '0', ),$atts)); // Grab the form or embedded $thing $falsePart = EvalElse($thing, 0); $thing = ($form) ? fetch_form($form) . (($falsePart) ? '' . $falsePart : '') : (($thing) ? $thing : ''); $colsform = (empty($colsform)) ? '' : fetch_form($colsform); $pagebit = array(); if ($pageform) { $pagePosAllowed = array("below", "above"); $paging = 1; $pageform = fetch_form($pageform); $pagepos = str_replace('smd_', '', $pagepos); $pagepos = do_list($pagepos, $delim); foreach ($pagepos as $pageitem) { $pagebit[] = (in_array($pageitem, $pagePosAllowed)) ? $pageitem : $pagePosAllowed[0]; } } // Make a unique hash value for this instance so the queries can be paged independently $uniq = ''; $md5 = md5($column.$table.$where.$query.$defaults); list($hashLen, $hashSkip) = explode(':', $hashsize); for ($idx = 0, $cnt = 0; $cnt < $hashLen; $cnt++, $idx = (($idx+$hashSkip) % strlen($md5))) { $uniq .= $md5[$idx]; } $pagevar = ($pagevar == 'SMD_QUERY_UNIQUE_ID') ? $uniq : $pagevar; $urlfilter = (!empty($urlfilter)) ? do_list($urlfilter, $delim) : ''; $urlreplace = (!empty($urlreplace)) ? do_list($urlreplace, $delim) : ''; if ($debug > 0) { echo "++ URL FILTERS ++"; dmp($urlfilter); dmp($urlreplace); } // Process any defaults $spc = ($strictfields) ? 0 : 1; $defaults = do_list($defaults, $delim); $dflts = array(); foreach ($defaults as $item) { $item = do_list($item, $paramdelim); if ($item[0] == '') continue; if (count($item) == 2) { $dflts[$item[0]] = smd_query_parse($item[1], array(''), array(''), array(''), $spc); } } if ($debug > 0) { echo "++ DEFAULTS ++"; dmp($dflts); } // Get a list of fields to escape $escapes = do_list($escape, $delim); foreach ($escapes as $idx => $val) { if ($val == '') { unset($escapes[$idx]); } } $rs = array(); $out = array(); $colout = $finalout = array(); $pageout = ''; // query overrides column/table/where if ($query) { $query = smd_query_parse($query, $dflts, $urlfilter, $urlreplace, $spc); $mode = ($mode == 'auto') ? ((preg_match('/(select|show)/i', $query)) ? 'output' : 'input') : $mode; if ($mode == 'input') { $rs = ($silent) ? @safe_query($query, $debug) : safe_query($query, $debug); } else { $rs = ($silent) ? @getRows($query, $debug) : getRows($query, $debug); } } else { if ($column && $table) { // TODO: Perhaps doSlash() these? $column = smd_query_parse($column, $dflts, $urlfilter, $urlreplace, $spc); $table = smd_query_parse($table, $dflts, $urlfilter, $urlreplace, $spc); $where = smd_query_parse($where, $dflts, $urlfilter, $urlreplace, $spc); $where = ($where) ? $where : "1=1"; $mode = 'output'; $rs = ($silent) ? @safe_rows($column, $table, $where, $debug) : safe_rows($column, $table, $where, $debug); } else { trigger_error("You must specify at least 1 'column' and a 'table'."); } } if ($mode == 'output') { $numrows = count($rs); $truePart = EvalElse($thing, 1); if ($rs) { if ($debug > 1) { echo "++ QUERY RESULT SET ++"; dmp($numrows . " ROWS"); dmp($rs); } if ($limit > 0) { $safepage = $thispage; $total = $numrows - $offset; $numPages = ceil($total/$limit); $pg = (!gps($pagevar)) ? 1 : gps($pagevar); $pgoffset = $offset + (($pg - 1) * $limit); // send paging info to txp:newer and txp:older $pageout['pg'] = $pg; $pageout['numPages'] = $numPages; $pageout['s'] = $pretext['s']; $pageout['c'] = $pretext['c']; $pageout['grand_total'] = $numrows; $pageout['total'] = $total; $thispage = $pageout; } else { $pgoffset = $offset; } $rs = array_slice($rs, $pgoffset, (($limit==0) ? 99999 : $limit)); $pagerows = count($rs); $replacements = $repagements = $colreplacements = array(); $page_rowcnt = ($count=="up") ? 0 : $pagerows-1; $qry_rowcnt = ($count=="up") ? $pgoffset-$offset : $numrows-$pgoffset-1; $first_row = $qry_rowcnt + 1; // Preserve any external context switch ($populate) { case 'article': $safe = ($thisarticle) ? $thisarticle : array(); break; case 'image': $safe = ($thisimage) ? $thisimage : array(); break; case 'file': $safe = ($thisfile) ? $thisfile : array(); break; case 'link': $safe = ($thislink) ? $thislink : array(); break; } foreach ($rs as $row) { foreach ($row as $colid => $val) { if ($page_rowcnt == 0 && $colsform) { $colreplacements['{'.$colid.'}'] = $colid; } // Construct the replacement arrays $replacements['{'.$colid.'}'] = (in_array($colid, $escapes) ? htmlspecialchars($val, ENT_QUOTES) : $val); if ($page_rowcnt == (($count=="up") ? $pagerows-1 : 0) && $pageform && $limit>0) { $prevpg = (($pg-1) > 0) ? $pg-1 : ''; $nextpg = (($pg+1) <= $numPages) ? $pg+1 : ''; $repagements['{smd_allrows}'] = $total; $repagements['{smd_pages}'] = $numPages; $repagements['{smd_prevpage}'] = $prevpg; $repagements['{smd_thispage}'] = $pg; $repagements['{smd_nextpage}'] = $nextpg; $repagements['{smd_row_start}'] = $first_row; $repagements['{smd_row_end}'] = $qry_rowcnt + 1; $repagements['{smd_rows_prev}'] = (($prevpg) ? $limit : 0); $repagements['{smd_rows_next}'] = (($nextpg) ? (($qry_rowcnt+$limit+1) > $total ? $total-$qry_rowcnt-1 : $limit) : 0); $repagements['{smd_query_unique_id}'] = $uniq; $smd_query_pginfo = $repagements; } } $replacements['{smd_allrows}'] = (($limit>0) ? $total : $numrows-$pgoffset); $replacements['{smd_rows}'] = $pagerows; $replacements['{smd_pages}'] = (($limit>0) ? $numPages : 1); $replacements['{smd_thispage}'] = (($limit>0) ? $pg : 1); $replacements['{smd_thisindex}'] = $page_rowcnt; $replacements['{smd_thisrow}'] = $page_rowcnt + 1; $replacements['{smd_cursorindex}'] = $qry_rowcnt; $replacements['{smd_cursor}'] = $qry_rowcnt + 1; if ($debug > 0) { echo "++ REPLACEMENTS ++"; dmp($replacements); } // Attempt to set up contexts to allow TXP tags to be used. // This facility relies on the correct columns being pulled out by the query: caveat utilitor switch ($populate) { case 'article': populateArticleData($row); $thisarticle['is_first'] = ($page_rowcnt == 1); $thisarticle['is_last'] = (($page_rowcnt + 1) == $pagerows); break; case 'image': $thisimage = image_format_info($row); break; case 'file': $thisfile = file_download_format_info($row); break; case 'link': $thislink = array( 'id' => $row['id'], 'linkname' => $row['linkname'], 'url' => $row['url'], 'description' => $row['description'], 'date' => $row['uDate'], 'category' => $row['category'], 'author' => $row['author'], ); break; } $out[] = ($preparse) ? strtr(parse($truePart), $replacements) : parse(strtr($truePart, $replacements)); $qry_rowcnt = ($count=="up") ? $qry_rowcnt+1 : $qry_rowcnt-1; $page_rowcnt = ($count=="up") ? $page_rowcnt+1 : $page_rowcnt-1; } if ($out) { if ($colreplacements) { $colout[] = ($preparse) ? strtr(parse($colsform), $colreplacements) : parse(strtr($colsform, $colreplacements)); } if ($repagements) { $pageout = ($preparse) ? strtr(parse($pageform), $repagements) : parse(strtr($pageform, $repagements)); } // Make up the final output if (in_array("above", $pagebit)) { $finalout[] = $pageout; } $finalout[] = doLabel($label, $labeltag).doWrap(array_merge($colout, $out), $wraptag, $break, $class, $breakclass, '', '', $html_id); if (in_array("below", $pagebit)) { $finalout[] = $pageout; } // Restore the paging outside the plugin container if ($limit > 0) { $thispage = $safepage; } // Restore the other contexts if (isset($safe)) { switch ($populate) { case 'article': $thisarticle = $safe; break; case 'image': $thisimage = $safe; break; case 'file': $thisfile = $safe; break; case 'link': $thislink = $safe; break; } } return join('', $finalout); } } else { return parse(EvalElse($thing, 0)); } } return ''; } // Returns a string with any ? variables replaced with their globals // URL Variables are optionally run through preg_replace() to sanitize them. // $pat is an array of regex search patterns // $rep is an array of regex search repalcements (default = '', i.e. remove whatever matches) function smd_query_parse($item, $dflts=array(''), $pat=array(''), $rep=array(''), $lax=true) { global $pretext, $thisarticle, $thisimage, $thisfile, $thislink, $variable; $item = html_entity_decode($item); // Sometimes pesky Unicode is not compiled in. Detect if so and fall back to ASCII if (!@preg_match('/\pL/u', 'a')) { $modRE = ($lax) ? '/(\?)([A-Za-z0-9_\- ]+)/' : '/(\?)([A-Za-z0-9_\-]+)/'; } else { $modRE = ($lax) ? '/(\?)([\p{L}\p{N}\p{Pc}\p{Pd}\p{Zs}]+)/' : '/(\?)([\p{L}\p{N}\p{Pc}\p{Pd}]+)/'; } $numMods = preg_match_all($modRE, $item, $mods); for ($modCtr = 0; $modCtr < $numMods; $modCtr++) { $modChar = $mods[1][$modCtr]; $modItem = trim($mods[2][$modCtr]); $lowitem = strtolower($modItem); $urlvar = $svrvar = ''; if (gps($lowitem) != '') { $urlvar = doSlash(gps($lowitem)); if ($urlvar && $pat) { $urlvar = preg_replace($pat, $rep, $urlvar); } } if (serverSet($modItem) != '') { $svrvar = doSlash(serverSet($modItem)); if ($svrvar && $pat) { $svrvar = preg_replace($pat, $rep, $svrvar); } } if (isset($variable[$lowitem]) && $variable[$lowitem] != '') { $item = str_replace($modChar.$modItem, $variable[$lowitem], $item); } else if ($svrvar != '') { $item = str_replace($modChar.$modItem, $svrvar, $item); } else if (isset($thisimage[$lowitem]) && !empty($thisimage[$lowitem])) { $item = str_replace($modChar.$modItem, $thisimage[$lowitem], $item); } else if (isset($thisfile[$lowitem]) && !empty($thisfile[$lowitem])) { $item = str_replace($modChar.$modItem, $thisfile[$lowitem], $item); } else if (isset($thislink[$lowitem]) && !empty($thislink[$lowitem])) { $item = str_replace($modChar.$modItem, $thislink[$lowitem], $item); } else if (array_key_exists($lowitem, $pretext) && !empty($pretext[$lowitem])) { $item = str_replace($modChar.$modItem, $pretext[$lowitem], $item); } else if (isset($thisarticle[$lowitem]) && !empty($thisarticle[$lowitem])) { $item = str_replace($modChar.$modItem, $thisarticle[$lowitem], $item); } else if ($urlvar != '') { $item = str_replace($modChar.$modItem, $urlvar, $item); } else if (isset($dflts[$lowitem])) { $item = str_replace($modChar.$modItem, $dflts[$lowitem], $item); } else { $item = str_replace($modChar.$modItem, $modItem, $item); } } return $item; } // Convenience functions to check if there's a prev/next page defined. Could also use smd_if function smd_query_if_prev($atts, $thing) { global $smd_query_pginfo; $res = $smd_query_pginfo && $smd_query_pginfo['{smd_prevpage}'] != ''; return parse(EvalElse(strtr($thing, $smd_query_pginfo), $res)); } function smd_query_if_next($atts, $thing) { global $smd_query_pginfo; $res = $smd_query_pginfo && $smd_query_pginfo['{smd_nextpage}'] != ''; return parse(EvalElse(strtr($thing, $smd_query_pginfo), $res)); }