PageRenderTime 49ms CodeModel.GetById 14ms RepoModel.GetById 1ms app.codeStats 0ms

/smd_lib/smd_lib.php

https://bitbucket.org/mrdale/txp-plugins
PHP | 581 lines | 410 code | 71 blank | 100 comment | 97 complexity | d42f48e7c368f1eac81e65eb571dae42 MD5 | raw file
  1. <?php
  2. // This is a PLUGIN TEMPLATE for Textpattern CMS.
  3. // Copy this file to a new name like abc_myplugin.php. Edit the code, then
  4. // run this file at the command line to produce a plugin for distribution:
  5. // $ php abc_myplugin.php > abc_myplugin-0.1.txt
  6. // Plugin name is optional. If unset, it will be extracted from the current
  7. // file name. Plugin names should start with a three letter prefix which is
  8. // unique and reserved for each plugin author ("abc" is just an example).
  9. // Uncomment and edit this line to override:
  10. $plugin['name'] = 'smd_lib';
  11. // Allow raw HTML help, as opposed to Textile.
  12. // 0 = Plugin help is in Textile format, no raw HTML allowed (default).
  13. // 1 = Plugin help is in raw HTML. Not recommended.
  14. # $plugin['allow_html_help'] = 1;
  15. $plugin['version'] = '0.36';
  16. $plugin['author'] = 'Stef Dawson';
  17. $plugin['author_uri'] = 'http://stefdawson.com/';
  18. $plugin['description'] = 'Shared function library used by smd_ plugins and others.';
  19. // Plugin load order:
  20. // The default value of 5 would fit most plugins, while for instance comment
  21. // spam evaluators or URL redirectors would probably want to run earlier
  22. // (1...4) to prepare the environment for everything else that follows.
  23. // Values 6...9 should be considered for plugins which would work late.
  24. // This order is user-overrideable.
  25. $plugin['order'] = '5';
  26. // Plugin 'type' defines where the plugin is loaded
  27. // 0 = public : only on the public side of the website (default)
  28. // 1 = public+admin : on both the public and admin side
  29. // 2 = library : only when include_plugin() or require_plugin() is called
  30. // 3 = admin : only on the admin side (no AJAX)
  31. // 4 = admin+ajax : only on the admin side (AJAX supported)
  32. // 5 = public+admin+ajax : on both the public and admin side (AJAX supported)
  33. $plugin['type'] = '2';
  34. // Plugin "flags" signal the presence of optional capabilities to the core plugin loader.
  35. // Use an appropriately OR-ed combination of these flags.
  36. // The four high-order bits 0xf000 are available for this plugin's private use
  37. if (!defined('PLUGIN_HAS_PREFS')) define('PLUGIN_HAS_PREFS', 0x0001); // This plugin wants to receive "plugin_prefs.{$plugin['name']}" events
  38. if (!defined('PLUGIN_LIFECYCLE_NOTIFY')) define('PLUGIN_LIFECYCLE_NOTIFY', 0x0002); // This plugin wants to receive "plugin_lifecycle.{$plugin['name']}" events
  39. $plugin['flags'] = '0';
  40. // Plugin 'textpack' is optional. It provides i18n strings to be used in conjunction with gTxt().
  41. // Syntax:
  42. // ## arbitrary comment
  43. // #@event
  44. // #@language ISO-LANGUAGE-CODE
  45. // abc_string_name => Localized String
  46. /** Uncomment me, if you need a textpack
  47. $plugin['textpack'] = <<<EOT
  48. #@admin
  49. #@language en-gb
  50. abc_sample_string => Sample String
  51. abc_one_more => One more
  52. #@language de-de
  53. abc_sample_string => Beispieltext
  54. abc_one_more => Noch einer
  55. EOT;
  56. **/
  57. // End of textpack
  58. if (!defined('txpinterface'))
  59. @include_once('zem_tpl.php');
  60. # --- BEGIN PLUGIN CODE ---
  61. // Software engineers look away now unless you wish to be horrified by the amount
  62. // of coupling and cohesion in these functions. I'm warning you... it's not pretty
  63. if (!class_exists('smd_MLP')) {
  64. class smd_MLP {
  65. var $smd_strings;
  66. var $smd_owner;
  67. var $smd_prefix;
  68. var $smd_lang;
  69. var $smd_event;
  70. function smd_MLP($plug, $prefx, $strarray, $lng='en-gb', $ev='public') {
  71. $this->smd_owner = $plug;
  72. $this->smd_prefix = $prefx;
  73. $this->smd_strings = $strarray;
  74. $this->smd_lang = $lng;
  75. $this->smd_event = $ev;
  76. register_callback(array(&$this, 'smd_Callback'), 'l10n.enumerate_strings');
  77. }
  78. function smd_Callback($event='l10n.enumerate_strings', $step='', $pre=0) {
  79. $r = array(
  80. 'owner' => $this->smd_owner,
  81. 'prefix' => $this->smd_prefix,
  82. 'lang' => $this->smd_lang,
  83. 'event' => $this->smd_event,
  84. 'strings' => $this->smd_strings,
  85. );
  86. return $r;
  87. }
  88. // Generic lookup
  89. // $what = key to look up
  90. // $args = any arguments the key is expecting for replacement
  91. function gTxt($what, $args = array()) {
  92. global $textarray;
  93. // Prepare the prefixed key for use
  94. $key = $this->smd_prefix . '-' . $what;
  95. $key = strtolower($key);
  96. // Grab from the global textarray (possibly edited by MLP) if we can
  97. if(isset($textarray[$key])) {
  98. $str = $textarray[$key];
  99. } else {
  100. // The string isn't in the localised textarray so fallback to using
  101. // the (non prefixed) string array in the plugin
  102. $key = strtolower($what);
  103. $str = (isset($this->smd_strings[$key])) ? $this->smd_strings[$key] : $what;
  104. }
  105. // Perform substitutions
  106. if(!empty($args)) {
  107. $str = strtr($str, $args);
  108. }
  109. return $str;
  110. }
  111. }
  112. }
  113. if (!function_exists("smd_doList")) {
  114. function smd_doList($lst, $rng=true, $sub="", $qte=true, $dlm=",", $lax=true) {
  115. global $thisarticle, $thisimage, $thisfile, $thislink, $pretext, $variable;
  116. $inc = $exc = array();
  117. $lst = do_list($lst, $dlm);
  118. // Sometimes pesky Unicode is not compiled in. Detect if so and fall back to ASCII
  119. if (!@preg_match('/\pL/u', 'a')) {
  120. $modRE = ($lax) ? '/(\?|\!)([A-Za-z0-9_\- ]+)/' : '/(\?|\!)([A-Za-z0-9_\-]+)/';
  121. } else {
  122. $modRE = ($lax) ? '/(\?|\!)([\p{L}\p{N}\p{Pc}\p{Pd}\p{Zs}]+)/' : '/(\?|\!)([\p{L}\p{N}\p{Pc}\p{Pd}]+)/';
  123. }
  124. foreach ($lst as $item) {
  125. $mod = 0; // 0 = include, 1 = exclude
  126. $numMods = preg_match_all($modRE, $item, $mods);
  127. for ($modCtr = 0; $modCtr < $numMods; $modCtr++) {
  128. // mod "type" is governed by the first one found only. i.e. if "article-?c!s" was used in one field
  129. // it would be an "include" of the word "article-" plus the category and section concatenated
  130. $mod = ($mods[1][0] === "!") ? 1 : 0;
  131. $modChar = $mods[1][$modCtr];
  132. $modItem = trim($mods[2][$modCtr]);
  133. $lowitem = strtolower($modItem);
  134. if (isset($variable[$lowitem])) {
  135. $item = str_replace($modChar.$modItem, $variable[$lowitem], $item);
  136. } else if (isset($thisimage[$lowitem])) {
  137. $item = str_replace($modChar.$modItem, $thisimage[$lowitem], $item);
  138. } else if (isset($thisfile[$lowitem])) {
  139. $item = str_replace($modChar.$modItem, $thisfile[$lowitem], $item);
  140. } else if (isset($thislink[$lowitem])) {
  141. $item = str_replace($modChar.$modItem, $thislink[$lowitem], $item);
  142. } else if (array_key_exists($lowitem, $pretext)) {
  143. $item = str_replace($modChar.$modItem, $pretext[$lowitem], $item);
  144. } else if (isset($_POST[$modItem])) {
  145. $item = str_replace($modChar.$modItem, $_POST[$modItem], $item);
  146. } else if (isset($_GET[$modItem])) {
  147. $item = str_replace($modChar.$modItem, $_GET[$modItem], $item);
  148. } else if (isset($_SERVER[$modItem])) {
  149. $item = str_replace($modChar.$modItem, $_SERVER[$modItem], $item);
  150. } else if (isset($thisarticle[$lowitem])) {
  151. $item = str_replace($modChar.$modItem, $thisarticle[$lowitem], $item);
  152. } else {
  153. $item = str_replace($modChar.$modItem, $modItem, $item);
  154. }
  155. }
  156. // Handle ranges of values
  157. $sitem = do_list($item, $dlm);
  158. foreach ($sitem as $idx => $elem) {
  159. if ($rng && preg_match('/^(\d+)\-(\d+)$/', $elem)) {
  160. list($lo, $hi) = explode("-", $elem, 2);
  161. $sitem[$idx] = implode($dlm, range($lo, $hi));
  162. }
  163. }
  164. $item = implode($dlm, $sitem);
  165. // Item may be empty; ignore it if so
  166. if ($item) {
  167. $item = do_list($item, $dlm);
  168. // Handle sub-categories
  169. if ($sub) {
  170. list($subtype, $level) = explode(":", $sub);
  171. $level = (empty($level)) ? 0 : $level;
  172. $level = (strtolower($level)=="all") ? 99999 : $level;
  173. $outitems = array();
  174. foreach ($item as $cat) {
  175. $cats = getTree(doslash($cat), $subtype);
  176. foreach ($cats as $jdx => $val) {
  177. if ($cats[$jdx]['level'] <= $level) {
  178. $outitems[] = $cats[$jdx]['name'];
  179. }
  180. }
  181. }
  182. $item = $outitems;
  183. }
  184. // Quote if asked
  185. $item = ($qte) ? doArray($item, 'doQuote') : $item;
  186. if ($mod === 0) {
  187. $inc = array_unique(array_merge($inc, $item));
  188. } else {
  189. $exc = array_unique(array_merge($exc, $item));
  190. }
  191. }
  192. }
  193. return array($inc, $exc);
  194. }
  195. }
  196. // Split a string on a pattern and allow integer ranges to be expanded
  197. if (!function_exists("smd_split")) {
  198. function smd_split($str, $allowRange=true, $splitat="/(,|,\s)+/", $pregopt = PREG_SPLIT_NO_EMPTY) {
  199. $retarr = array();
  200. if ((substr($splitat,0,1) == "/") && (substr($splitat, strlen($splitat)-1, 1) == "/")) {
  201. $pat = $splitat;
  202. } else {
  203. $pat = '/['.$splitat.']+/';
  204. }
  205. $elems = preg_split($pat, $str, -1, $pregopt);
  206. foreach ($elems as $item) {
  207. $item = trim($item);
  208. $negate = false;
  209. // Does the item start with a negation character
  210. if (substr($item,0,1) === "!") {
  211. $negate = true;
  212. $item = substr($item,1);
  213. }
  214. // Is the item an integer list range
  215. if ($allowRange && preg_match('/^(\d+)\-(\d+)$/', $item)) {
  216. list($lo, $hi) = explode("-", $item, 2);
  217. $rng = range($lo, $hi);
  218. // Reapply the negation if necessary
  219. for($idx = 0; $idx < count($rng); $idx++) {
  220. $rng[$idx] = (($negate) ? "!" : "") . $rng[$idx];
  221. }
  222. $retarr = array_merge($retarr, $rng);
  223. } else {
  224. $retarr[] = (($negate) ? "!" : "") . $item;
  225. }
  226. }
  227. return $retarr;
  228. }
  229. }
  230. if (!function_exists("smd_doDblQuote")) {
  231. function smd_doDblQuote($val) {
  232. return '"'.$val.'"';
  233. }
  234. }
  235. if (!function_exists("smd_removeQSVar")) {
  236. function smd_removeQSVar($url, $key) {
  237. $url = preg_replace('/(.*)(\?|&)' . $key . '=[^&]+?(&)(.*)/i', '$1$2$4', $url . '&');
  238. $url = substr($url, 0, -1);
  239. return ($url);
  240. }
  241. }
  242. if (!function_exists("smd_addQSVar")) {
  243. function smd_addQSVar($url, $key, $value) {
  244. $url = smd_removeQSVar($url, $key);
  245. if (strpos($url, '?') === false) {
  246. return ($url . '?' . $key . '=' . $value);
  247. } else {
  248. return ($url . '&' . $key . '=' . $value);
  249. }
  250. }
  251. }
  252. // DEPRECATED: for backwards compatibility only
  253. if (!function_exists("smd_getSubCats")) {
  254. function smd_getSubCats($parent,$cattype) {
  255. return getTree($parent,$cattype); //getTree() or getTreePath()??
  256. }
  257. }
  258. // DEPRECATED: for backwards compatibility only
  259. if (!function_exists("smd_getOpts")) {
  260. function smd_getOpts($str, $allowed, $idprefix="", $allowRange=true, $splitat="/(,|,\s)+/", $pregopt = PREG_SPLIT_NO_EMPTY) {
  261. global $pretext, $thisarticle;
  262. $out = array();
  263. $notout = array();
  264. $matches = smd_split($str, $allowRange, $splitat, $pregopt);
  265. // An array that tells the loop what to do with each of the valid strings
  266. // arg1: type (1=exact match, 2=anywhere within string, 3=custom field)
  267. // arg2: prefix, if any
  268. // arg3: variable to substitute
  269. // arg4: extra check, if applicable
  270. // arg5: store in the in/exclude list (1=include; 2=exclude)
  271. $opt = array(
  272. "?c" => array(2, "", $pretext['c'], "1", 1),
  273. "!c" => array(2, "", $pretext['c'], "1", 2),
  274. "?s" => array(2, "", $pretext['s'], "1", 1),
  275. "!s" => array(2, "", $pretext['s'], "1", 2),
  276. "?q" => array(2, "", $pretext['q'], "1", 1),
  277. "!q" => array(2, "", $pretext['q'], "1", 2),
  278. "?t" => array(2, "", $thisarticle['url_title'], '$thisarticle!=NULL', 1),
  279. "!t" => array(2, "", $thisarticle['url_title'], '$thisarticle!=NULL', 2),
  280. "?id" => array(1, $idprefix, $pretext['id'], '$thisarticle!=NULL', 1),
  281. "!id" => array(1, $idprefix, $pretext['id'], '$thisarticle!=NULL', 2),
  282. "?" => array(3, "", "", '$thisarticle!=NULL', 1),
  283. "!" => array(3, "", "", '$thisarticle!=NULL', 2),
  284. );
  285. for ($idx = 0; $idx < count($matches); $idx++) {
  286. $matched = false;
  287. $thismatch = $matches[$idx];
  288. foreach ($opt as $var => $args) {
  289. $opvar = ($args[4] == 1) ? "out" : "notout";
  290. switch ($args[0]) {
  291. case 1:
  292. if (($thismatch === $var) && in_array($var,$allowed)) {
  293. $matched = true;
  294. if ($args[2] != "" && $args[3]) {
  295. $rep = str_replace($var, $args[1].$args[2], $thismatch);
  296. if (!in_array($rep, ${$opvar})) {
  297. ${$opvar}[] = $rep;
  298. }
  299. }
  300. }
  301. break;
  302. case 2:
  303. $pat = '/\\'.$var.'$|\\'.$var.'[^A-Za-z0-9]/';
  304. if ((is_int(smd_pregPos($pat, $thismatch, $fnd))) && in_array($var,$allowed)) {
  305. $matched = true;
  306. if ($args[2] != "" && $args[3]) {
  307. $rep = str_replace($var, $args[1].$args[2], $thismatch);
  308. if (!in_array($rep, ${$opvar})) {
  309. ${$opvar}[] = $rep;
  310. }
  311. }
  312. }
  313. break;
  314. case 3:
  315. $len = strlen($var);
  316. if ((substr($thismatch,0,$len) === $var) && in_array($var."field",$allowed)) {
  317. $matched = true;
  318. // Use the given field name; which may be a comma-separated sublist.
  319. // Split off the field name from the question mark
  320. $fieldname = substr($thismatch,$len);
  321. if (($args[3]) && (isset($thisarticle[strtolower($fieldname)]))) {
  322. $fieldContents = $thisarticle[strtolower($fieldname)];
  323. } else {
  324. $fieldContents = $fieldname;
  325. }
  326. if (!empty($fieldContents)) {
  327. $subout = smd_split(strip_tags($fieldContents), $allowRange, $splitat, $pregopt);
  328. foreach ($subout as $subname) {
  329. if (!in_array($subname, ${$opvar})) {
  330. ${$opvar}[] = $subname;
  331. }
  332. }
  333. }
  334. }
  335. break;
  336. }
  337. if ($matched) {
  338. break;
  339. }
  340. }
  341. if (!$matched) {
  342. // Assign the variable verbatim
  343. if (!in_array($thismatch, $out)) {
  344. $out[] = $thismatch;
  345. }
  346. }
  347. }
  348. return array($out,$notout);
  349. }
  350. }
  351. // Stolen from php.net: strpos page comments...
  352. if (!function_exists("smd_pregPos")) {
  353. function smd_pregPos($sPattern, $sSubject, &$FoundString, $iOffset = 0) {
  354. $FoundString = null;
  355. if (preg_match($sPattern, $sSubject, $aMatches, PREG_OFFSET_CAPTURE, $iOffset) > 0) {
  356. $FoundString = $aMatches[0][0];
  357. return $aMatches[0][1];
  358. } else {
  359. return false;
  360. }
  361. }
  362. }
  363. //... and array_combine...
  364. if (!function_exists("array_combine")) {
  365. function array_combine($arr1,$arr2) {
  366. $out = array();
  367. foreach($arr1 as $key1 => $value1) {
  368. $out[$value1] = $arr2[$key1];
  369. }
  370. return $out;
  371. }
  372. }
  373. //... and htmlspecialchars_decode
  374. if (!function_exists("htmlspecialchars_decode")) {
  375. function htmlspecialchars_decode($string, $quote_style = ENT_COMPAT) {
  376. return strtr($string, array_flip(get_html_translation_table(HTML_SPECIALCHARS, $quote_style)));
  377. }
  378. }
  379. # --- END PLUGIN CODE ---
  380. if (0) {
  381. ?>
  382. <!--
  383. # --- BEGIN PLUGIN CSS ---
  384. <style type="text/css">
  385. #smd_help { line-height:1.3 ;}
  386. #smd_help code { font-weight:bold; font: 105%/130% "Courier New", courier, monospace; background-color: #FFFFCC;}
  387. #smd_help code.block { font-weight:normal; border:1px dotted #999; background-color: #f0e68c; display:block; margin:10px 10px 20px; padding:10px; }
  388. #smd_help a:link, #smd_help a:visited { color: blue; text-decoration: none; border-bottom: 1px solid blue; padding-bottom:1px;}
  389. #smd_help a:hover, #smd_help a:active { color: blue; text-decoration: none; border-bottom: 2px solid blue; padding-bottom:1px;}
  390. #smd_help h1 { color: #369; font: 20px Georgia, sans-serif; margin: 0; text-align: center; }
  391. #smd_help h2 { border-bottom: 1px solid black; padding:10px 0 0; color: #369; font: 17px Georgia, sans-serif; }
  392. #smd_help h3 { color: #693; font: bold 12px Arial, sans-serif; letter-spacing: 1px; margin: 10px 0 0;text-transform: uppercase;}
  393. #smd_help h4 { font: bold 11px Arial, sans-serif; letter-spacing: 1px; margin: 10px 0 0 ;text-transform: uppercase; }
  394. #smd_help .att-name { font-weight:bold; }
  395. #smd_help .mand { background:#eee; border:1px dotted #999; }
  396. #smd_help table {width:100%; text-align:center; padding-bottom:1em;}
  397. #smd_help td, #smd_help th {border:1px solid #999; padding:.5em 0;}
  398. </style>
  399. # --- END PLUGIN CSS ---
  400. -->
  401. <!--
  402. # --- BEGIN PLUGIN HELP ---
  403. <div id="smd_help">
  404. <h1>smd_ plugin library</h1>
  405. <p>Offers no public textpattern tags. It is simply a shared library of common functions used by smd_ plugins.</p>
  406. <h2>Changelog</h2>
  407. <ul>
  408. <li>v0.1 07-02-25 Initial public release</li>
  409. <li>v0.2 07-03-03 Added: <span class="caps"><span class="caps">MLP</span></span> (Multi-Lingual Pack) library support</li>
  410. <li>v0.21 07-03-06 Added: integer range functionality. <code>smd_getAtts</code> now takes a RegEx arg</li>
  411. <li>v0.21a 07-03-21 Fixed: Character ranges ignored (thanks mrdale)</li>
  412. <li>v0.21b 07-04-02 Fixed: Sticky article support in <code>smd_getAtts</code> (thanks pieman)</li>
  413. <li>v0.21c 07-07-29 Fixed: Numeric ranges in categories (thanks wolle)</li>
  414. <li>v0.21d 07-08-03 Fixed: Negation with multiple elements</li>
  415. <li>v0.21e 07-09-14 Fixed: Ability to leave empty splitRange parameters intact</li>
  416. <li>v0.22 07-09-20 Fixed: Undefined index warnings (thanks Ambitiouslemon). Enhanced matches so spaces are allowed in strings (thanks DrRogg)</li>
  417. <li>v0.23 07-04-09 <span class="caps">BETA</span> : Added the FuzzyFind class and getWord function. getAtts() now allows <code>?q</code></li>
  418. <li>v0.3 07-10-29 Rewrote <code>smd_getAtts</code> as <code>smd_getOpts</code> to allow replaced vars within text. Deprecated <code>smd_getAtts</code>, added <code>smd_pregPos</code>. Changed <code>smd_splitRange</code> as <code>smd_split</code> to allow ranges to be switched on or off. Deprecated <code>smd_splitRange</code>. Added generic <span class="caps">MLP</span> class support (<code>smd_MLP</code>). Deprecated <code>smdMLP</code> array, <code>smd_gTxt</code> and <code>smd_getCaller</code>. Made <code>smd_FuzzyFind</code> and <code>smd_getWord</code> official</li>
  419. <li>v0.31 07-11-27 Removed <code>smdMLP</code> array, <code>smd_gTxt</code> and <code>smd_getCaller</code>. Deprecated <code>smd_getSubCats</code>. Added a few PHP4 helper functions</li>
  420. <li>v0.32 08-03-29 Removed <code>smd_getAtts</code> and <code>smd_getSubCats</code>. Deprecated <code>smd_getOpts</code> and <code>smd_split</code>. Added <code>smd_doList</code>. Moved the <code>smd_FuzzyFind</code> class and <code>smd_getWord</code> into the smd_fuzzy_find plugin where they should have been all along</li>
  421. <li>v0.33 08-12-02 Undeprecated(!) <code>smd_split</code> since it&#8217;s actually quite useful ; extended <code>smd_doList</code> to encompass <code>$thisimage</code> (for future) and <code>$variable</code> ; fixed bug in <code>smd_doList</code> when using subcats</li>
  422. <li>v0.34 08-12-13 <code>smd_doList</code> uses a unicode regex</li>
  423. <li>v0.35 09-02-24 <code>smd_doList</code> fixed ranges in &#8216;?&#8217; variables (thanks koobs)</li>
  424. <li>v0.36 09-04-02 <code>smd_doList</code> falls back to <span class="caps">ASCII</span> if Unicode not available (thanks RedFox / mlarino / decoderltd)</li>
  425. </ul>
  426. <h2>Function Reference</h2>
  427. <p><strong>smd_addQSVar</strong><br />
  428. <strong>smd_removeQSVar</strong></p>
  429. <p>Add or remove a query string variable to the given <span class="caps">URL</span>, taking into account any existing variables that may be in the <span class="caps">URL</span> already. &#8216;Add&#8217; takes three arguments, &#8216;Remove&#8217; just takes the first two:</p>
  430. <ol>
  431. <li>The <span class="caps">URL</span> string to add to/remove from</li>
  432. <li>The id of the querystring (the bit before the = sign)</li>
  433. <li>The value of the new querystring (the bit after the = sign)</li>
  434. </ol>
  435. <p>e.g. <code>smd_addQSVar($thisarticle[&#39;url_title&#39;], &#39;tpg&#39;, 15);</code> would add <code>tpg=15</code> to the current article&#8217;s <span class="caps">URL</span>. If there are no other variables currently in the <span class="caps">URL</span>, it is added with a question mark, otherwise it is appended with an ampersand.</p>
  436. <p><strong>smd_doList</strong></p>
  437. <p>Return an expanded list of items with the following properties:</p>
  438. <ol>
  439. <li>Anything containing &#8216;?&#8217; or &#8216;!&#8217; is checked for a match with a <span class="caps">TXP</span> field (<code>&lt;txp:variable /&gt;</code>, image, file, link, global article, url <span class="caps">POST</span>/GET/SERVER, or individual article, in that order)</li>
  440. <li>Any ranges of items are expanded (e.g. 4-7 =&gt; 4,5,6,7) if the <code>rng</code> option permits it</li>
  441. <li><span class="caps">TXP</span> fields may themselves be lists or ranges</li>
  442. <li>Anything that is not a <span class="caps">TXP</span> field is used verbatim</li>
  443. <li>The items are returned as 2 lists; inclusion and exclusion</li>
  444. </ol>
  445. <p>Args ( [*] = mandatory ) :
  446. <ol>
  447. <li>[*] lst = the list as a delimited string</li>
  448. <li>rng = whether to allow ranges or not (bool). Default = true</li>
  449. <li>sub = the type of subcategory to traverse (image, file, link, article, none=&#8221;&#8220;) and how many levels to go down (e.g. image:2). Default = &#8216;&#8217;</li>
  450. <li>qte = whether to quote each item in the array or not (bool). Default = true</li>
  451. <li>dlm = the delimiter (string). Default = &#8220;,&#8221;</li>
  452. <li>lax = Whether to be lax or strict about what characters constitute a field; primarily whether spaces are allowed in, say, custom fields. Default = &#8220;1&#8221;</li>
  453. </ol></p>
  454. <p><strong>smd_getOpts</strong></p>
  455. <p>Deprecated as it is mostly superseded by smd_doList; this one is clunkier but has $idprefix so it remains for now. It searches the passed string for predetermined sequences of characters and, if that sequence is in the given $allowed array, replaces it as follows:</p>
  456. <ul>
  457. <li>?c = current global category (!c = not current category)</li>
  458. <li>?s = current section (!s = not current section)</li>
  459. <li>?t = current article title (!t = not current title)</li>
  460. <li>?id = current article ID, prepended with $idprefix (!id = not current ID)</li>
  461. <li>?q = current query term (!q = not current query term)</li>
  462. <li>?field = contents of the current article&#8217;s field (could be a comma-separated list)</li>
  463. <li>!field = not the contents of the current article&#8217;s field (could be a comma-separated list)</li>
  464. </ul>
  465. <p>Integer ranges (e.g. 1-5) will be expanded into their individual values if the $allowRange option is true; anything else is returned verbatim. It outputs two arrays: the 1st contains items for inclusion, the 2nd contains items for exclusion.</p>
  466. <p>Args ( [*] = mandatory ) :
  467. <ol>
  468. <li>[*] The string to search for matches</li>
  469. <li>[*] An array containing shortcuts that are &#8220;allowed&#8221; to be found in the string (?c, ?s, ?t, ?field etc)</li>
  470. <li>The prefix for ?id strings</li>
  471. <li>Boolean indicating whether to allow range expansion or not</li>
  472. <li>RegEx string to split options at (see smd_split)</li>
  473. <li>preg_split option (see smd_split)</li>
  474. </ol></p>
  475. <p><strong>smd_split</strong></p>
  476. <p>Returns an array of items from a string of (usually) comma-separated values. If any values contain ranges of numbers like 1-5 that need &#8216;expanding&#8217; first (and $allowRange is true), they are dealt with. Takes the following arguments ( [*] = mandatory args) :</p>
  477. <ol>
  478. <li>[*] The string to split</li>
  479. <li>Boolean indicating whether to allow range expansion or not (i.e. 1-5 becomes 1,2,3,4,5)</li>
  480. <li>The regular expression character classes to match. If a full RegEx starting and ending with &#8216;/&#8217; characters is supplied, the expression is used verbatim. Without the &#8216;/&#8217; characters, the expression is treated as a list of character classes to find. Defaults to &#8220;/(,|,\s)+/&#8221; which is a comma, or comma and a whitespace character.</li>
  481. <li>preg_split option constant as defined in the php manual</li>
  482. </ol>
  483. <p><strong>smd_MLP</strong><br />
  484. Instantiate one of these to handle <acronym title="Multi-Lingual Pack"><span class="caps">MLP</span></acronym> in your plugin like this:</p>
  485. <p>1) Declare a unique global variable, e.g. global $myPlug<br />
  486. 2) Define your default string replacement array (doesn&#8217;t need to be global), e.g:</p>
  487. <p> $myStrings = array (&#8220;msg1&#8221; =&gt; &#8220;This is message 1&#8221;, &#8220;msg2&#8221; =&gt; &#8220;This is message 2&#8221;);</p>
  488. <p>3) Create an <span class="caps">MLP</span> handler:</p>
  489. <p> $myPlug = new smd_MLP(&#8220;plugin_name&#8221;, &#8220;plugin_prefix&#8221;, $myStrings);</p>
  490. <p>4) That&#8217;s it! There are two optional args to smd_MLP:
  491. a) the default (full) language to use, e.g &#8220;da-dk&#8221;. Defaults to &#8220;en-gb&#8221;.
  492. b) the interface the strings are for. Choose from &#8220;public&#8221; (the default), &#8220;admin&#8221; or &#8220;common&#8221;</p>
  493. <p>5) To use a replacement string in your code:
  494. a) Make sure to import the unique global variable: e.g. global $myPlug;
  495. b) Call $myPlug-&gt;gTxt(&#8220;messageID&#8221;); [ e.g. $myPlug-&gt;gTxt(&#8220;msg1&#8221;) ]
  496. c) If you want to replace any args in your message string, pass an associative array as the 2nd arg to gTxt()</p>
  497. <p><strong>smd_doDblQuote</strong></p>
  498. <p>Alternative to the core&#8217;s doQuote(). This one dbl-quotes instead of sgl-quotes</p>
  499. <p><strong>smd_pregPos</strong></p>
  500. <p>Lifted from one of the comments in the <span class="caps">PHP</span> manual, this just looks for a RegEx string within another, returning the matches it finds and the position of the first match.</p>
  501. <p><strong>array_combine</strong></p>
  502. <p>PHP4 equivalent of the standard PHP5 function, lifted from php.net</p>
  503. <p><strong>htmlspecialchars_decode</strong></p>
  504. <p>PHP4 equivalent of the standard PHP5 function, lifted from php.net</p>
  505. </div>
  506. # --- END PLUGIN HELP ---
  507. -->
  508. <?php
  509. }
  510. ?>