'ContentAction')); if($ContentCfgLogViewer) SDVA($HandleActions, array('contentlog' => 'ContentActionLog')); $EditFunctions[] = 'ContentAfterSave'; array_unshift($EditFunctions, 'ContentClearProperties'); # Default embeddable types which get inserted directly in the output text ContentRegisterType('inline', null, 'txt', null, null); ContentRegisterType('safe', null, 'txt', null, null); ContentRegisterType('raw'); $ContentCacheEnable = ContentCfgCacheEnabled; $ContentPageNamePat = "!?[-\\w.\\/\\x80-\\xff]*"; // a valid PageName Markup('(:content:)', 'fulltext', '/\\(:content\s+(.*?)\s*:\\)\n?(.*?)\\(:contentend:\\)/es', "PRR(ContentDirective(\$pagename, ContentHandleFullText(PSS('\$2')), ParseArgs(PSS('\$1'))))"); Markup('(:contentlist:)', '<(:contentcurrent:)', '/\\(:contentlist\s+(.*?)\s*:\\)/es', "PRR(ContentDirective(\$pagename, null, ParseArgs(PSS('\$1'))))"); # Internal directive, do not use in wikipages! MarkupSamePass('(:contentcurrent:)', '>(:content:)', array( '\\(:contentset\s+(\\w+)\s+(\\w+)\s*:\\)' => "PRR(ContentSetPointer('\$1', '\$2'))", '\\{\\$\\/\\.\\.([\\w:,.\\/]+)(~\\w+)(\\+)?\\}' => "PRR('{\$/'.ContentCurrent('type').'..$1$2$3}')", '\\{\\$\\/([\\w:,.\\/]+)(\\+)?\\}' => "PRR('{\$/\$1~'.ContentCurrent('name').'\$2}')"), 'e'); Markup('{PageName$/cpath~name}', '>(:contentcurrent:)', "/\\{($ContentPageNamePat)?".'\\$(\\/[\\w:,.\\/]+~\\w+)(\\+)?\\}/e', "PRR(ContentPV(\$pagename, PSS('\$0'), '+' == '\$3'))"); # Internal directive, do not use in wikipages! Markup('(:contentimages:)', '>{PageName$/cpath~name}', '/\\(:contentimages\s+(.*?)\s*:\\)/e', "ContentMultiImages(PSS('\$1'))"); Markup('[[*|name]]', '

').' ', $list); } // Markup: Take a list of URLs and enumerated using the same text function ContentEnumAlink($url1, $urls, $text) { $eurls = explode(' ', $url1.$urls); foreach($eurls as $k => $url) { if($url) $links[]= "[[$url|".($k+1)."]]"; } return "$text(".implode(' ', $links).")"; } // Internal Directive: Set the current content pointer (name, type) function ContentSetPointer($type, $name) { global $ContentCurrent; $ContentCurrent['type']= $type; $ContentCurrent['names'][$type]= $name; } // Internal Directive: Get the current content pointer (name, type) function ContentCurrent($def, $type=null) { global $ContentCurrent; if($type === null) $type = $ContentCurrent['type']; if($type !== null) { $name = $ContentCurrent['names'][$type]; if($def === 'type') return $type; if($def === 'name') return $name; if($def === 'type name') return "$type $name"; } } // Directive: Register some content from a directive and/or // get a list of output types from a directive function ContentDirective($cpn, $csrc, $args) { global $ContentTypes, $ContentTypeNames; $type = $args[''][0]; if ($type === null) return; $name = $args[''][1]; if($ContentTypes[$type]['directive'] === false) return; $pn = $cpn; if($csrc !== null) $set = ContentSave($cpn, $csrc, $type, $name, $args['defargs'])."\n"; elseif(isset($args['page'])) $pn = $args['page']; if($name === null) $name = $ContentTypeNames[$type]; $dargs = ContentGetProp($cpn, $pn, $type, $name, 'args'); $types = ContentTypesText($cpn, $pn, $type, $name, $args, $dargs); return $set.$types; } // Markup: Creates a link for a cpath, even embedded or inline // types (so that users can expilicitly get links to the text // of the inline types). Unless the $nocheck is set, URLs that // create blank outputs are blanked. function ContentPV($cpn, $cpath, $nocheck) { $cp = ContentParsePath($cpath, $cpn); if(!$nocheck) { $cp = ContentCPFillData($cpn, $cp); $out = ContentGetCP($cp); if(is_array($out)) { foreach($out as $cpath) $urls[] = ContentPV($cpn, $cpath, $nocheck); return implode(' ', $urls); } if (!$out) return; } return ContentURL($cp, $cpn); } // API: Register a Type function ContentRegisterType($type, $mime=null, $ext=null, $deflist=null, $directive=false, $handler=null) { global $ContentTypes; if(!$type) return false; $ts['type'] = $type; $ts['mime'] = $mime; if($deflist !== null) $ts['list'] = $deflist; if($ext === '') $ts['ext'] = $type; else $ts['ext'] = $ext; $ts['handler'] = $handler; $ts['directive'] = $directive; $ContentTypes[$type] = $ts; if($directive) { if($directive === true) $directive = $type; Markup("(:$directive:)", '<(:content:)', "/\\(:$directive(\s+.*?)?:\\)(.*?)\\(:${directive}end:\\)/s", "(:content $type\$1:)\$2(:contentend:)"); } } // API: Register a Converter function ContentRegConverter($intype, $outtype, $fnc, $cnv=null) { global $ContentConverters, $ContentIndex; if ($cnv === null) $cnv = $intype .'2'. $outtype; $ContentConverters[$cnv]['intype'] = $intype; $ContentConverters[$cnv]['outtype'] = $outtype; $ContentConverters[$cnv]['fnc'] = $fnc; // [in_out][intype][outtype] -> converter (~eventually, multi) // [out_in][outtype][intype] -> converter (~eventually, multi) // Multi paths simply default to the last one I think, will be enhanced. // by creating converter arrays and merging arrays. // I have not considered loops yet, will they crash, or worse, infinite loop? // Converters cnv_i can create our intype from itype foreach((array)$ContentIndex['out_in'][$intype] as $itype => $cnv_i) { // Make sure that they now can create our outtype from their itype $ContentIndex['in_out'][$itype][$outtype] = $cnv_i; $ContentIndex['out_in'][$outtype][$itype] = $cnv_i; // Converters cnv_o can create otype from our outtype foreach((array)$ContentIndex['in_out'][$outtype] as $otype => $cnv_o) { // Make sure that they can now create otype from all // the itypes of cnv_i $ContentIndex['in_out'][$itype][$otype] = $cnv_i; $ContentIndex['out_in'][$otype][$itype] = $cnv_i; } } // Add the new converters stuff to the indexes $ContentIndex['in_out'][$intype][$outtype] = $cnv; $ContentIndex['out_in'][$outtype][$intype] = $cnv; // Converters cnv_o can create otype from our outtype foreach((array)$ContentIndex['in_out'][$outtype] as $otype => $cnv_o) { // Make sure that we can generate their otype from our intype $ContentIndex['in_out'][$intype][$otype] = $cnv; $ContentIndex['out_in'][$otype][$intype] = $cnv; } } // API: Register an FS Converter function ContentRegFSConverter($intype, $outtype, $cmdfmt, $cnv=null, $fnc=null) { global $ContentConverters; if ($cnv === null) $cnv = $intype .'2'. $outtype; $ContentConverters[$cnv]['cmdfmt'] = $cmdfmt;; $ContentConverters[$cnv]['argfnc'] = $fnc; ContentRegConverter($intype, $outtype, 'ContentFSConverter', $cnv); } // Lookup and link to all the output types of a type. function ContentTypesText($cpn, $pn, $type, $name, $args=null, $dargs=null) { global $ImgExtPattern; $cpaths = ContentPathsFrom($type, $name); $cargs = ContentParseCnvArgs($args['args'], $type); $dcargs = ContentParseCnvArgs($dargs, $type); $cpaths = ContentApplyCArgs($cpaths, $cargs); $cpaths = ContentApplyCArgs($cpaths, $dcargs); $types = ContentFilterTypes($cpaths, $args); $embed= $args['embed'] != strtolower("false"); if(in_array('nocheck', $args[''], true)) $nocheck = "+"; foreach($types as $type => $cpath) { $cpath = "{"."$pn\$$cpath$nocheck}"; if($type == 'inline' || $type == 'safe' || $type == 'raw') { $cp = ContentCPFillData($cpn, ContentParsePath($cpath)); $inline = ContentGetCP($cp); $esc = array('escape' => 0); if($type != 'raw') $inline = htmlentities($inline); if($type == 'safe') $inline = MarkupToHTML($pn, $inline, $esc); if($type != 'inline') $inline = Keep($inline); } elseif($embed && preg_match("/$ImgExtPattern/", '.'.$type, $m)) $ilinks[] = "$cpath"; else $tlinks[] = "[[$cpath | $type]]"; } if($ilinks) $out = '(:contentimages '.implode(' ', $ilinks).':)'; if($inline) { if($ilinks) $out .= '

'; $out .= $inline; } if($tlinks) { if($ilinks) $out .= '

'; $out .= implode(' ', $tlinks); } return $out; } // Apply a ',' comma separated list to another list function ContentApplyOptList($deflist, $optlist) { $opts = explode(',', $optlist); foreach($deflist as $opt) $list[$opt] = $opt; foreach($opts as $opt) if ($opt{0} != '+' && $opt{0} != '-') unset($list); foreach($opts as $opt) { if ($opt{0} === '+') $list[substr($opt, 1)] = $opt; elseif($opt{0} === '-') unset($list[substr($opt, 1)]); else $list[$opt] = $opt; } return $list; } // Filter the list of types function ContentFilterTypes($types, $args){ global $ContentTypes; $type = $args[''][0]; $list = $args['list']; $olist = (array) $types; if(!isset($args['list']) || $list === 'default') $list = 'defaults'; if($list === 'defaults') { if(isset($ContentTypes[$type]['list'])) $olist = ContentApplyOptList(array_keys($olist), $ContentTypes[$type]['list']); else $list = 'all'; } if($list === 'none') unset($olist); $olist = (array)$olist; if(isset($args['types'])) $olist = ContentApplyOptList(array_keys($olist), $args['types']); foreach($types as $type => $cpath) if(isset($olist[$type])) $out[$type] = $cpath; return (array)$out; } // Return the cpath(s) from one type to another type function ContentPath2($inseg, $outseg, $cp=null) { global $ContentConverters, $ContentIndex; $itseg = ContentParseTseg($inseg); $intype = $itseg['type']; $otseg = ContentParseTseg($outseg, $intype); $outtype = $otseg['type']; if($intype == $outtype) { if(!$otseg['cnv']) $otseg['cnv'] = $itseg['cnv']; if(!$otseg['args']) $otseg['args'] = $itseg['args']; return ContentMkSeg($otseg); } if($cp['type'] == null) $cp['type'] = $intype; if($cp['tsegs'] == null) $cp['tsegs'][] = $itseg; $cnv = $otseg['cnv']; if($ContentConverters[$cnv]['outtype'] !== $outtype) $cnv=null; if(!$cnv) $cnv = $ContentIndex['in_out'][$intype][$outtype]; if(!$cnv) return '/'; $otype = $ContentConverters[$cnv]['outtype']; if ($otype == $outtype) $args = $otseg['args']; $cp['tsegs'][] = array('type'=>$otype, 'cnv'=>$cnv, 'args'=>$args); if ($otype != $outtype) return ContentPath2($otype, $outseg, $cp); return ContentMkPath($cp); } // Retrieve a content's source/properties from the PCACHE function ContentGetProp($cpn, $pn, $type, $name, $cprop=null) { global $FmtPV, $ContentCfgPropPrefix, $ContentTypes, $PCache; if($ContentTypes[$type]['directive'] === false) return; // forbidden $prop = "$ContentCfgPropPrefix${type}_$name"; if($cprop) $prop .= ".$cprop"; $FmtPV[$prop]="\$page['$prop']"; // For some reason pagevar != property for current page // Pmwiki should check auth for current page if(MakePageName($cpn, $pn) === $cpn) return $PCache[$pn]["=p_$prop"]; if(!CondAuth($pn, 'read')) return; // unauthorized $val = PageVar($cpn, $prop, $pn); return $val; # echo "CPN:$cpn PN:$pn TYPE:$type NAME:$name CPROP:$cprop VAL:$val
"; } // Set a content's source/properties from the PCACHE function ContentSetProp($pn, $type, $name, $val, $cprop=null) { global $SaveProperties, $ContentCfgPropPrefix; $prop = "$ContentCfgPropPrefix${type}_$name"; if($cprop) $prop .= ".$cprop"; $SaveProperties[] = $prop; SetProperty($pn, $prop, $val); } // Clear any content page properties for a wikipage array function ContentClearProperties($pn,&$page,&$new) { global $SaveProperties, $PCache, $ContentCfgPropPrefix, $ContentEditing, $EnablePost; $ContentEditing = true; if($EnablePost) ContentClearCache($pn); foreach($new as $k=>$v) if(substr($k, 0, strlen($ContentCfgPropPrefix)) == $ContentCfgPropPrefix) { unset($PCache[$pn]["=p_$k"]); $SaveProperties[] = "$k"; } } function ContentHandleFullText($fulltext) { return str_replace(array('<', '>', '&', '<:vspace>', '\"'), array('<', '>', '&', '', '"'), $fulltext); } // Fill a cp struct with a content's data from the PCACHE function ContentCPFillData($cpn, $cp) { // Do we eventually want to return false on unautorized? $cp['data'] = ContentGetProp($cpn, $cp['pagename'], $cp['type'], $cp['name']); $defargs = ContentGetProp($cpn, $cp['pagename'], $cp['type'], $cp['name'], 'args'); $args = ContentParseCnvArgs($defargs, $cp['type']); return ContentCPApplyCArgs($cp, $args); } // Insert the Content as an attribute in the wiki page text function ContentSave($pn, $csrc, $type, $name='', $defargs=null) { global $ContentTypes, $ContentTypeNames; if (!$type) return; if ($name == '') $name = ++$ContentTypeNames[$type]; $handler = $ContentTypes[$type]['handler']; if ($handler) $csrc = $handler($pn, $type, $name, $csrc); ContentSetProp($pn, $type, $name, $csrc); ContentSetProp($pn, $type, $name, $defargs, 'args'); if(isset($_GET['contentclear'])) ContentClearCache($pn); return "(:contentset $type $name:)"; } // Convert a cpath or cp struct to a URL // ~we no longer seem to need cpath support here // withouth it, cpn can be replaced with cp['pagename'] function ContentURL($cppath, $cpn) { global $ContentEditing, $ContentCfgPreviewKey; if($cppath == '/') return; if(is_array($cppath)) $cp = $cppath; else $cp = ContentParsePath($cppath, $cpn); $cpath = ContentMkPath($cp); $ext = $cp['tsegs'][count($cp['tsegs'])-1]['ext']; $cargs = "action=content"; if ($ContentEditing && isset($_POST['preview'])) { $cp = ContentCPFillData($cpn, $cp); if($ContentCfgPreviewKey) { $md5 = md5(ContentMkPath($cp).$cp['data'].$ContentCfgPreviewKey); $cargs .= "&content_md5=".urlencode($md5); } $cargs .= "&content_data=".urlencode($cp['data']); } $cargs .= "&content=$cpath".($ext ? ".$ext":''); $fname = $cp['name'].($ext ? ".$ext":''); $url = FmtPageName("\$ScriptUrl", $cp['pagename']); $pn = FmtPageName("\$FullName", $cp['pagename']); // We always use this format even with clean URLs so that // the file (pre-query string) part of the URL ends in // a filename and extension. Some browsers will use this // filename when saving the content. $url .= "/$fname?n=$pn&$cargs"; return $url; } // Lookup all the output types of a type. // Returns an array indexed by otypes. function ContentPathsFrom($itype, $name=null) { global $ContentIndex; $cpaths[$itype] = "/$itype~$name"; foreach((array) $ContentIndex['in_out'][$itype] as $otype =>$cnv) { $cpaths[$otype] = ContentPath2($itype, $otype); if($name) $cpaths[$otype] = $cpaths[$otype]."~$name"; } return $cpaths; } // Apply converter arguments to cpaths function ContentApplyCArgs($cpaths, $cargs) { foreach((array) $cpaths as $otype => $cpath) { $cp = ContentParsePath($cpath); $cp = ContentCPApplyCArgs($cp, $cargs); $cpaths[$otype] = ContentMkPath($cp); } return $cpaths; } // Apply converter arguments to a cp struct function ContentCPApplyCArgs($cp, $cargs) { foreach($cp['tsegs'] as $k => $tseg) { $targs = $tseg['args']; if ($targs === null) $cp['tsegs'][$k]['args'] = $cargs[$tseg['cnv']]; } return $cp; } // Take an args list and output arguments indexed by converters function ContentParseCnvArgs($args, $itype) { foreach(explode(',', $args) as $targs) { if($targs === '' || $targs === null) continue; $cp = ContentParsePath("/$itype..$targs"); $tseg = $cp['tsegs'][count($cp['tsegs']) -1]; $oargs[$tseg['cnv']] = $tseg['args']; } return $oargs; } // Convert a tseg struct to a seg function ContentMkSeg($tseg, $ptype=null) { $type = $tseg['type']; $cnv = $tseg['cnv']; $args = $tseg['args']; if($args !== null) $args = ".$args"; if ($ptype && $cnv == $ptype .'2'. $type) return "/$type$args"; return "/$cnv$args:$type"; } // Convert a cp struct to a cpath without {$...} // (they are needed/used in url cpaths) function ContentMkPath($cp) { $ptype = $cp['type']; $cpath = "/$ptype"; $args = $cp['tsegs'][0]['args']; if($args !== null) $cpath .= ".$args"; for($i=1; $i< count($cp['tsegs']) ; $i++) { $tseg = $cp['tsegs'][$i]; $cpath .= ContentMkSeg($tseg, $ptype); $ptype = $tseg['type']; } if(isset($cp['name'])) $cpath .= '~'. $cp['name']; return $cpath; } // Traverse the type section of a cpath and expand it function ContentExpandPath($tpath) { while($otpath != $tpath) { $otpath=$tpath; # otypes ending with a dot work by virtue of the dot staying in place $tpath = preg_replace('|/([^/]+?)/?\.\./?([^/~.]+(\.[^/~.]+)*)|e', 'ContentPath2("$1", "$2")', $tpath); $tpath = preg_replace('|//+|', '/', $tpath); } return $tpath; } // Parses a cpath segment and returns a tseg struct function ContentParseTseg($tspath, $itype=null) { global $ContentTypes, $ContentConverters, $ContentIndex; preg_match('|^([^:]*)(?::(.*))?$|', $tspath, $m); list($x, $cnvseg, $type) = $m; preg_match('/^(.*?)(\.(.*))?$/', $type, $m); list($x, $type, $dot, $targs) = $m; if($targs == null) $targs=''; if($dot == null) $targs=null; preg_match('/^(.*?)(\.(.*))?$/', $cnvseg, $m); list($x, $cnv, $dot, $cargs) = $m; if($cargs == null) $cargs=''; if($dot == null) $cargs= $targs; if (!$type) { if($itype) { $otype = $ContentConverters[$cnv]['outtype']; if(isset($ContentTypes[$cnv]) || !$otype) { $type = $cnv; $cnv = $itype .'2'. $type; if($ContentConverters[$cnv]['outtype'] !== $type) $cnv=null; } else $type = $otype; } else { if(isset($ContentTypes[$cnv])) $type = $cnv; $cnv = null; } } return array('type'=>$type, 'cnv'=>$cnv, 'args'=>$cargs, 'mime' => $ContentTypes[$type]['mime'], 'ext' => $ContentTypes[$type]['ext'], 'intype' => $itype, 'inext' => $ContentTypes[$itype]['ext'] ); } // Convert a cpath to a cp struct // Internal short cpaths we shave to deal with: // /abcm (no ~) // /abcm/ps~1 // {PN$/abcm} function ContentParsePath($cpath, $pn=null) { global $ContentPageNamePat; preg_match("|^\{?(?:($ContentPageNamePat)?".'\$)?(/.*?)(?:~([^~.}]*)(?:\.([^.}]*))?)?}?$|', $cpath, $m); list($x, $cppn, $tpath, $name, $ext) = $m; if($cppn) $pn = $cppn; $tpath = ContentExpandPath($tpath); $tspaths = explode('/', $tpath); foreach($tspaths as $tspath) { if($tspath) { $tseg = ContentParseTseg($tspath, $prevtype); $prevtype = $tseg['type']; $tsegs[] = $tseg; } } return array('name'=>$name, 'type'=>$tsegs[0]['type'], 'tsegs'=>$tsegs, 'pagename' => $pn); } // Get the content output for a cp struct // cp['data'] must be set and no authorization is done here! /* Walk the cpath recursively for each path segment processing the data with the appropriate fitler along the way. For each path segment, this function gets called first to check for any cached version of the current path segment output, if nothing is cached it calls itself again for the same path segment so that it can process and store the results in the cache for next time. */ function ContentGetCP($cp, $cache=true) { global $ContentCfgPropPrefix, $ContentConverters; if(!isset($cp['data'])) return null; $out = ContentCacheGet($cp); if($out !== null) return $out; if($cache) return ContentCacheSave($cp, ContentGetCP($cp, false)); $tsegs= $cp['tsegs']; $name= $cp['name']; $c= count($tsegs); $l= $c - 1; if($c == 0) return null; // ~ContentError($cp, HTTP_INTERNALSERVER); not for wiki pages! if($c == 1) return $cp['data']; $cnv = $tsegs[$l]['cnv']; if (!$cnv) return null; // ~ContentError($cp, HTTP_INTERNALSERVER); not for wiki pages! $fnc = $ContentConverters[$cnv]['fnc']; $intype = $ContentConverters[$cnv]['intype']; $outtype = $ContentConverters[$cnv]['outtype']; $ptype = $tsegs[$l-1]['type']; $ctype = $tsegs[$l]['type']; if (!$fnc || $intype != $ptype || $outtype != $ctype) { if (!$fnc) echo "CONTENT_CONVERTER ($cnv) function is blank\n"; if ($intype != $ptype) echo "CONTENT_CONVERTER ($cnv) input type does not match ($intype != $ptype)\n"; if ($outtype != $ctype) echo "CONTENT_CONVERTER ($cnv) output type does not match ($outtype != $ctype)\n"; sleep(10); return null; // ~sleep should be only for writting? // ~ContentError($cp, HTTP_INTERNALSERVER); not for wiki pages! } $args = $tsegs[$l]['args']; $cpi = $cp; array_pop($cpi['tsegs']); $out = ContentGetCP($cpi); if(!$out) return false; // do not cache any further! if(is_array($out)) { foreach($out as $k => $cpath) { $cpo = ContentParsePath($cpath, $cp['pagename']); $cpo['tsegs'][$l] = $tsegs[$l]; $out[$k] = ContentMkPath($cpo); } return $out; } $out = $fnc($cp, $cnv, $intype, $outtype, $args, $out); if(is_array($out)) foreach($out as $k => $v) { $cpo = $cp; $cpo['tsegs'][$l]['args'] = $k; $out[$k] = ContentMkPath($cpo); } return $out; } // Called by pmwiki when the logfile for a page is requested function ContentActionLog($pn, $auth="read") { $log = ContentGetLog($pn, $auth); if($log === false) { echo "You are not authorized to view this log, sorry.
"; return; } echo $log; } // Called by pmwiki during saves after page has been written function ContentAfterSave($pn,&$page,&$new) { global $FmtV; if (@$_POST['preview']) { $log = ContentGetLog($pn, 'edit'); ContentClearCache($pn); if(!$log) return; $FmtV['$PreviewText'] = $FmtV['$PreviewText'] . "\n
\n$log"; } } // Called by pmwiki when the content for a cpath is requested function ContentAction($pn, $auth="read") { global $ContentCfgPreviewKey, $ContentCfgPropPrefix, $ContentCacheEnable, $ContentTypes; if(isset($_GET['contentclear'])) ContentClearCache($pn); $cpath = stripmagic($_GET["content"]); $cp = ContentParsePath($cpath, $pn); if(isset($_REQUEST["content_data"])) { if($ContentTypes[$cp['type']]['directive'] === false) ContentError($cp, HTTP_FORBIDDEN); if(!CondAuth($pn, 'edit')) ContentError($cp, HTTP_UNAUTHORIZED); $ContentCacheEnable = false; $cp['data'] = stripmagic($_REQUEST["content_data"]); if($ContentCfgPreviewKey) { $md5 = md5(ContentMkPath($cp).$cp['data'].$ContentCfgPreviewKey); if ($_GET['content_md5'] != $md5) ContentError($cp, HTTP_UNAUTHORIZED); } } else { $page = RetrieveAuthPage($cp['pagename'], 'read', true, READPAGE_CURRENT); $prop = $ContentCfgPropPrefix.$cp['type']."_".$cp['name']; if(!isset($page[$prop])) ContentError($cp, HTTP_NOTFOUND); $cp['data'] = $page[$prop]; $args = ContentParseCnvArgs($page[$prop.'.args'], $cp['type']); $cp = ContentCPApplyCArgs($cp, $args); } $out = ContentGetCP($cp); if(!$out) ContentError($cp, HTTP_NOCONTENT); $c = count($cp['tsegs']); $mime = $cp['tsegs'][$c-1]['mime']; if ($mime) header("Content-type: ". $mime); echo "$out"; # The main output, not a debug statement :) } function ContentCachePageDir($pn) { global $ContentCfgCacheDir, $ContentCache, $ContentCacheEnable; if(!$ContentCacheEnable) return null; if (@$_POST['preview']) { $dir = $ContentCache[$pn]['dir']; if(!$dir) { $dir = ContentTmpDir(); $ContentCache[$pn]['dir']= $dir; } } else $dir = "$ContentCfgCacheDir/cache/$pn"; return $dir; } // API: Output text to the cp's page logfile function ContentLog($cp, $text) { global $ContentCacheEnable; if(!$ContentCacheEnable) return $data; $dir = ContentCachePageDir($cp['pagename']); $file = "$dir/Content.log"; file_put_contents($file, $text, FILE_APPEND); } function ContentGetLog($pn, $auth="read") { global $ContentCfgLogViewer, $ContentCacheEnable; if(!$ContentCacheEnable) return null; $dir = ContentCachePageDir($pn); $file = "$dir/Content.log"; if(CondAuth($pn, $ContentCfgLogViewer)) return false; $log = @file_get_contents($file); if(!$log) return; $log = implode("
\n", explode("\n", $log)); return "LOG FILE for $pn

$log

"; } // Convert a cp struct to a cached filename function ContentCacheFileName($cp) { global $ContentCacheEnable; if(!$ContentCacheEnable) return null; $cpath = ContentMkPath($cp); $cpath = preg_replace('|/|', '~', substr($cpath,1)); $dir = ContentCachePageDir($cp['pagename']); $ext = $cp['tsegs'][count($cp['tsegs'])-1]['ext']; $file = "$dir/$cpath".($ext ? ".$ext":''); return $file; } // Clear the cache for a wikipage function ContentClearCache($pn) { global $ContentCacheEnable; if(!$ContentCacheEnable) return; ContentRmTree(ContentCachePageDir($pn)); } // API: Import a file into the cache system function ContentCachePutFile($cp, $file) { global $ContentCacheEnable; if(!$ContentCacheEnable) { @unlink($file); return; } if(!file_exists($file)) return; $cfile = ContentCacheFileName($cp); ContentLog($cp, "=** IMPORTED: $file\n TO CACHE: $cfile\n\n"); @rename($file, $cfile); } // Save data in the cache system // if data is null or false, do not save! function ContentCacheSave($cp, $data) { global $ContentCacheEnable; if(!$ContentCacheEnable || $data === null || $data === false) return $data; $file = ContentCacheFileName($cp); $filea = "$file.array"; if(is_array($data)) { @unlink($file); if(file_exists($filea)) return $data; } else { @unlink($filea); if(file_exists($file)) return $data; } $dir = dirname($file); mkdirp($dir); if(is_array($data)) { $file = $filea; $sdata = serialize($data); file_put_contents($file, $sdata); } else { file_put_contents($file, $data); } ContentLog($cp, "=** CACHED: $file\n\n"); return $data; } // Get data from the cache // null means data was not in cache or cache is disabled function ContentCacheGet($cp) { global $ContentCacheEnable; if(!$ContentCacheEnable) return null; $file = ContentCacheFileName($cp); if(file_exists("$file.array")) { return unserialize(file_get_contents("$file.array")); } if(! file_exists($file)) return null; return file_get_contents($file); } // API: Escape an array of arguments safely for shell use function ContentEscapeShellArgs($args) { foreach($args as $k=>$v) $out[$k]= escapeshellarg($v); return (array)$out; } // Useless absraction, deprecated, but still used by music.php function ContentDir($cp) { return ContentTmpDir(); } // This runs a system command feeding it input and output files function ContentFSConverter($cp, $cnv, $intype, $outtype, $args, $data) { global $ContentConverters; $c = count($cp['tsegs']) - 1; ContentLog($cp, "FS Converter: ==== $cnv ====\n"); $fnc = $ContentConverters[$cnv]['cmd']; if($fnc) { $cmd = $fnc($cp, $cnv, $intype, $outtype, $args); } else { $cmd = $ContentConverters[$cnv]['cmdfmt']; $fnc = $ContentConverters[$cnv]['argfnc']; if($fnc) { ContentLog($cp, "REPLACING ARGS($args): $cmd\n"); if($args) { $argv = $fnc($cp, $cnv, $intype, $outtype, explode('.', $args)); $args = implode(" ", ContentEscapeShellArgs($argv)); } $cmd = str_replace('${a}', $args, $cmd); } } $dir = ContentTmpDir(); $iext = $cp['tsegs'][$c]['inext']; $oext = $cp['tsegs'][$c]['ext']; $tmpi = "$dir/I_$cnv".($iext ? ".$iext" : ''); $tmpo = "$dir/O_$cnv".($oext ? ".$oext" : ''); $cmd = str_replace('${i}', $tmpi, $cmd); $cmd = str_replace('${o}', $tmpo, $cmd); file_put_contents($tmpi, $data); ContentLog($cp, "EXECUTING: $cmd\n"); exec($cmd, $err); if($err) ContentLog($cp, "ERROR:\n".implode("\n", $err)."\n"); $out = @file_get_contents($tmpo); ContentCachePutFile($cp, $tmpo); if (!$ContentConverters[$cnv]['keep']) ContentRmTree($dir); if(!$out) return ''; // Cache empty results too return $out; } // Create a temporary file (atomic on unix) function ContentTmpname($dir, $pre='', $post='') { $tmpc = tempnam($dir, $pre); $tmpn = $tmpc . $post; if ($tmpc != $tmpn) { $win = DIRECTORY_SEPARATOR == '\\' ? true : false; $link = $win ? 'rename' : 'link'; while (! @$link($tmpc, $tmpn)) { $tmpn = $tmpc . $i++ . $post; if ($i > 10000) return false; } if(! $win) unlink($tmpc); } return $tmpn; } function ContentTmpDir($dir=null, $pre='', $post='') { global $ContentCfgCacheDir; if($dir ===null) $dir = "$ContentCfgCacheDir/tmp"; mkdirp($dir); $tmp = "$dir/$pre".(++$i).$post; while (! @mkdir($tmp, 0755)) { if ($i > 10000) return false; $tmp = "$dir/$pre".(++$i).$post; } return $tmp; } // rm -rf function ContentRmTree($dir) { $dir = escapeshellarg($dir); exec("rm -rf $dir"); } if ( !function_exists('file_put_contents') && !defined('FILE_APPEND') ) { define('FILE_APPEND', 1); function file_put_contents($n, $d, $flag = false) { $mode = ($flag == FILE_APPEND || strtoupper($flag) == 'FILE_APPEND') ? 'a' : 'w'; $f = @fopen($n, $mode); if ($f === false) return false; if (is_array($d)) $d = implode($d); $bytes = fwrite($f, $d); fclose($f); return $bytes; } } define('HTTP_FORBIDDEN', '403 Request Forbidden'); define('HTTP_NOTFOUND', '404 Content Not Found'); define('HTTP_NOCONTENT', '204 No Content'); define('HTTP_UNAUTHORIZED', '401 Unauthorized'); define('HTTP_INTERNALSERVER', '500 Internal Server Error'); function ContentError($cp, $err, $exit=true) { header("HTTP/1.0 $err"); $cpath = '{'.$cp['pagename'].'$'.ContentMkPath($cp).'}'; echo "PmWiki Content Recipe For: $cpath
"; echo "
\n$err"; if($exit) exit(); };