Much ado about scripting, Linux & Eclipse: card subject to change

2007-07-12

You got wiki in my webpage!

Inspired by Karl's post about transclusion of wiki content in other webpages, I thought I'd post my solution to this issue, as used to include all the EMF-tagged wiki documents in our docs page.

Caveats:

  1. it's prone to breakage (if the wiki markup engine changes, as it did recently to drop the "/index.php/" prefix on URLs in category pages); and
  2. it only works for turning category pages into Phoenix-styled bulleted lists, but that's pretty cool IMHO.

Here's the code:

/* convert a wiki category page into a series of <li> items */
function wikiCategoryToListItems($category)
{
 $collecting = false;
 $wiki_contents = "";
 
 // insert wiki content
 $host = "wiki.eclipse.org";
 $url = "/Category:" . $category;
 $vars = "";

 $header = "Host: $host\r\n";
 $header .= "User-Agent: PHP Script\r\n";
 $header .= "Content-Type: application/x-www-form-urlencoded\r\n";
 $header .= "Content-Length: ".strlen($vars)."\r\n";
 $header .= "Connection: close\r\n\r\n";

 $fp = fsockopen($host, 80, $errno, $errstr, 30);
 if (!$fp) {
  $out .=  "<li><i>$errstr ($errno)</i></li>\n";
 } else {
  fputs($fp, "GET $url"."?"."$vars  HTTP/1.1\r\n");
  fputs($fp, $header.$vars);
  while (!feof($fp)) {
   $wiki_contents .= fgets($fp, 128);
  }
  fclose($fp);
  $wiki_contents = explode("\n",$wiki_contents);
 }
 if ($wiki_contents && is_array($wiki_contents))
 {
  foreach ($wiki_contents as $wline)
  {
   $matches = null;

   // find stop line
   if (false !== strpos($wline, "printfooter"))
   {
    $collecting = false;
    break;
   }
   
   // collect link(s)
   if ($collecting && 
    preg_match_all("#<a href=\"/([^\"]+)\" title=\"([^\"]+)\">([^\<\>]+)</a>#", 
     $wline, $matches, PREG_SET_ORDER))
   {
    if (is_array($matches) && sizeof($matches)>0)
    {
     foreach ($matches as $match)
     {
      $out .= "<li><a href=\"http://wiki.eclipse.org/" . 
       $match[1] . "\" title=\"" . $match[2] . "\">" . $match[3] . "</a></li>\n";
     }
    }
   }
   
   // find start line
   if (false !== strpos($wline, "Articles in category \"". $category ."\""))
   { 
    $collecting = true;
   }
  }
 }
 return $out;
}

Then, I use this in our docs/index.php thus:

echo "<div id=\"midcolumn\">\n";
$contents = file("docs.xml");
$matches = null;
foreach ($contents as $line) { 
 if (false !== strpos($line, "<!-- DO NOT REMOVE: placeholder for wiki content -->"))
 {
  print wikiCategoryToListItems("EMF");
 } 
 else
 {
  print $line;
 }
}
echo "</div>\n";

And the result is that as new docs are tagged with [[Category:EMF]] in the wiki, they automatically appear in two places: http://wiki.eclipse.org/Category:EMF and http://www.eclipse.org/modeling/emf/docs/#references.

Obviously, this is not a full solution for full-page transclusion, like Karl's idea of using iframes, but does solve the issue of not having to produce lists of links on the website, when the wiki will do it for you, automatically.

2 comments:

SDiZ said...

$vars is always empty, Content-Length header is always zero

Nick said...

True, but if you need to pass querystring data, it can be specified as $data = "name=value&name2=value2";