Extension talk:Graphical Category Browser

I get the extension to work. Graphviz renders the images and the message 'rendered with..' but if i click on the image (name of a category) i get an empty white page.The normal categoryoverview don't work anymore, too. I user MW 1.10 on Wamp. Any Idea? -- 13.8.2007

same problem as above
Hi

I also have the same problem as described above. any solutions, plz?

Jack

How to I install graphwiz?
I'm confused about how to install graphwiz? Which version should I chose (debian, ubuntu?? Executable Packages from AT&T?, Java?)

Is this extension for a local use? I don't have any control on which software my web provider have installed on his system...

To install it on JumpBox VM, which uses Ubuntu, go to a shell windows and:
 * 1) apt-get update /* updte avail packages */
 * 2) apt-get install graphviz /* install graphviz */

dot will be installed in /usr/bin/dot

Solved problem with white page
Hi I propably solved problem with white page described above.

Please disable this line in code:

$wgHooks['CategoryPageView'][] = 'xyCategoryGraphHook';

so it will be:

//$wgHooks['CategoryPageView'][] = 'xyCategoryGraphHook';

what i have done wrong? ERROR
I have no image to display. in the apache log i am getting always usr/bin/dot: symbol lookup error: /usr/lib/libcairo.so.2: undefined symbol: FT_Library_SetLcd

in cache .dot is created, .png is corrupted

if i compile .dot manually, i'll get a graph without errors

Example Please
Any examples of this extension?

Solved problem with white page on Windows
The problem was in the shell_exec commands in the lines 170 to 180 while generating the png- and mapfile, now it works.

The script
serveFile) die; header("HTTP/1.1 404 Not Found"); die("404 Not Found "); } //install special page $wgExtensionFunctions[] = 'xyfCategoryBrowserSetup'; $wgExtensionCredits['specialpage'][] = array(       'name' => 'Xypron Category Browser',        'author' =>'xypron',        'description' => 'Graphviz graphs for categories',        'url' => 'http://www.xypron.de'); // Setup Special Page function xyfCategoryBrowserSetup { global $IP, $wgMessageCache, $wgHooks; //$wgHooks['CategoryPageView'][] = 'xyCategoryGraphHook'; require_once($IP . '/includes/SpecialPage.php'); SpecialPage::addPage(new SpecialPage('Xygraphicalcategorybrowser', '', true, 'xyfGraphicalCategoryBrowser', false)); $wgMessageCache->addMessages( array( 'xygraphicalcategorybrowser' => 'Graphical Category Browser', 'xyrenderedwith'   => 'rendered with')    ); $wgMessageCache->addMessages( array( 'xygraphicalcategorybrowser' => 'Graphische Kategorieuebersicht', 'xyrenderedwith'   => 'gezeichnet mit'),    'de'); } function xyfGraphicalCategoryBrowser { $cap = new xyCategoriesPage; $cap->doQuery; $cap->doDot('xycategorybrowser'); $cap->showImg('xycategorybrowser'); } class xyCategoriesPage { var $debug = false; var $dot = ""; function doQuery($title = null) { global $wgOut; error_reporting(0); $redirections= Array; $nodes=Array; $this->dot = "digraph a {\nsize=\"8,20\";\nrankdir=LR;\nnode [height=0 style=\"filled\", shape=\"box\", font=\"Helvetica-Bold\", fontsize=\"10\", color=\"#00000\"];\n"; $dbr =& wfGetDB( DB_SLAVE ); $sql= $this->getSQLCategories($title); $res = $dbr->query( $sql ); # Only read at most $num rows, because $res may contain the whole 1000 for ( $i = 0; $obj = $dbr->fetchObject($res); $i++ ) { $l_title = Title::makeTitle(NS_CATEGORY, $obj->cat); $color = "#CCFFCC"; if($obj->redirect==1) $color = "#FFCCCC"; if($obj->virtual == 1) $color = "#FFFFCC"; $nodes[$obj->cat] = array(       'color' => $color,        'url'   => $l_title->getFullURL,        'peri'  => 1        ); if ($title && $obj->cat == $title->getDBkey) { $nodes[$obj->cat]['peri']=2; }     if ($obj->redirect) { $article = new article($l_title); if ($article) { $text = $article->getContent; $rt = Title::newFromRedirect($text); if ($rt) { if (NS_CATEGORY == $rt->getNamespace) { $redirections[$l_title->getDBkey] = $rt->getDBkey; if (!$nodes[$rt->getDBkey]){ $nodes[$rt->getDBkey] = array(                 'color' => "#CCFFCC",                  'url'   => $rt->getFullURL,                  'peri'  => 1                  ); }             }            }          }        }      }    $sql= $this->getSQLCategoryLinks($title); $res = $dbr->query( $sql ); for ( $i = 0; $obj = $dbr->fetchObject( $res ); $i++ ) { $cat_from = Title::makeName(NS_CATEGORY, $obj->cat_from); $cat_to  = Title::makeName(NS_CATEGORY, $obj->cat_to); if (@!$nodes[$obj->cat_to]){ $rt = Title::makeTitle(NS_CATEGORY, $obj->cat_to); $nodes[$rt->getDBkey] = array(         'color' => "#FF0000",          'url'   => $rt->getFullURL,          'peri'  => ($title && $rt->getDBkey == $title->getDBkey)? 2 : 1          ); }     if (!$redirections[$obj->cat_from] &&  $redirections[$obj->cat_from] != $obj->cat_to) { $this->dot .= "\"$obj->cat_to\" -> \"$obj->cat_from\" [dir=back];\n"; }     }    foreach( $redirections as $cat_from => $cat_to) { $this->dot .= "\"$cat_to\" -> \"$cat_from\" [color=\"#FF0000\", dir=back];\n"; }   foreach( $nodes as $l_DbKey=>$properties ) { $l_title = Title::makeTitle(NS_CATEGORY, $l_DbKey); $this->dot .= "\"$l_DbKey\" [URL=\"{$properties['url']}\", peripheries={$properties['peri']}, fillcolor=\"{$properties['color']}\"];\n"; }   $this->dot .= "}\n"; if ($this->debug) $wgOut->addWikiText("<"."pre>$this->dot<"."pre>"); } /** * Save dot file and generate png and map file * @param title to generate md5 for filename */ function cacheAge( $title ) { $md5 = md5($title); $docRoot = $this->cachePath; $fileMap = "$docRoot$md5.map"; if (!file_exists($fileMap)) return false; return time - filemtime($fileMap); } /** * Save dot file and generate png and map file * @param title to generate md5 for filename */ function doDot( $title ) { global $wgOut; global $xyDotPath; $md5 = md5($title); $docRoot = $this->cachePath; $fileDot = "$docRoot$md5.dot"; $fileMap = "\"$docRoot$md5.map\""; $filePng = "\"$docRoot$md5.png\"";

$this->file_put_contents($fileDot, $this->dot); if ($xyDotPath) {

if ($this->debug) $wgOut->addWikiText("$xyDotPath -Tpng -o$filePng <\"$fileDot\""); #$result = shell_exec("$xyDotPath -T png -o $filePng \"$fileDot\""); $WshShell = new COM("WScript.Shell"); $ret = $WshShell->Exec("$xyDotPath -T png -o $filePng \"$fileDot\"");

if ($this->debug) $wgOut->addWikiText("$xyDotPath -Tcmap -o$fileMap <\"$fileDot\""); #$map = shell_exec("$xyDotPath -T cmap -o $fileMap <\"$fileDot\""); $WshShell2 = new COM("WScript.Shell"); $ret2 = $WshShell2->Exec("$xyDotPath -T cmap -o $fileMap \"$fileDot\"");

} }

/** * serveFile * * This function is used to deliver the PNG file to the client. * Client side cache behaviour is controlled here. * This is necessary to get a match between the html and the image. */ function serveFile { global $xyCategoriesMaxAge; // Get filename from GET parameter if(isset($_GET['png'])) { $filename = @$_GET['png']; }  else { return false; }  // Check filename is valid if (preg_match('/\\W/',$filename))return false; $docRoot = $this->cachePath; $file = "$docRoot$filename.png"; // Check file exists if (!file_exists($file)) return false; // Get filetime $time = @filemtime($file); // Get filesize $size = @filesize($file); $etag = md5("$time|$size"); // Get "Last-Modified" if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { $oldtime=strtotime(current(explode(';',$_SERVER['HTTP_IF_MODIFIED_SINCE']))); }  // Get "ETag" if (isset($_SERVER['HTTP_IF_NONE_MATCH'])) { $oldetag=explode(',',$_SERVER['HTTP_IF_NONE_MATCH']); }  // If either is unchanged the file is not modified. if ( (isset($oldtime) && $oldtime == $time ) ||     (isset($oldetag) && $oldetag == $etag ) ) { header('HTTP/1.1 304 Not Modified'); header('Date: '.gmdate('D, d M Y H:i:s').' GMT'); header('Server: PHP'); header("ETag: $etag"); return true; }  // Send headers header('HTTP/1.1 200 OK'); header('Date: '.gmdate('D, d M Y H:i:s').' GMT'); header('Server: PHP'); header('Last-Modified: '.gmdate('D, d M Y H:i:s',$time).' GMT'); header('Expires: '.gmdate('D, d M Y H:i:s',$time+$xyCategoriesMaxAge).' GMT'); // Supply the filename that is proposed when saving the file to disk header("Content-Disposition: inline; filename=cat.png"); header("ETag: $etag"); header("Accept-Ranges: bytes"); header("Content-Length: ".(string)(filesize($file))); header("Connection: close\n"); header("Content-Type: image/png"); // Send file $h = fopen($file, 'rb'); fpassthru($h); fclose($h); return true; } /** * Output the image to the OutputPage object. * @param title to generate md5 for filename */ function showImg( $title ) { global $wgOut; global $wgUploadPath, $wgScriptPath; $docRoot = $this->cachePath; $md5 = md5($title); $fileMap = "$docRoot$md5.map"; // Get name of this script this will keep it working after renaming $path_parts = pathinfo(__FILE__); $script = $path_parts['basename']; if (file_exists($fileMap)) { $map = $this->file_get_contents($fileMap); if ($this->debug) $wgOut->addWikiText("<"."pre>$map<"."/pre>"); $URLpng = "$wgScriptPath/extensions/$script?png=$md5"; $wgOut->addHTML("$map"); $wgOut->addWikiText(       wfMsg('xyrenderedwith')." Graphviz - Graph Visualization Software".        ', '.date("Y-m-d H:i:s.", filemtime($fileMap))."\n\n"); return true; }   else { return false; }   } /** * @return directory for graphviz files */ function cachePath { global $xyCategoriesCache; $path = pathinfo(__FILE__); $path = $path['dirname'].$xyCategoriesCache; if (substr( php_uname, 0, 7 ) == "Windows") $path = preg_replace('/\\//', '\\',$path); if (!is_dir($path)) { mkdir($path, 0775); }   return $path; } function getSQLCategories( $title = null ) { global $wgOut; $NScat = NS_CATEGORY; $dbr =& wfGetDB(DB_SLAVE); $categorylinks = $dbr->tableName('categorylinks'); $page         = $dbr->tableName('page'); $sql = "SELECT\n". "   page_title AS cat,\n". "   page_is_redirect AS redirect,\n". "   0 AS virtual\n". " FROM $page\n". " WHERE\n". "   page_namespace={$NScat}\n". "UNION\n". "SELECT\n". "   cl_to as cat,\n". "   0 AS redirect,\n". "   1 AS virtual\n". " FROM $categorylinks\n". " LEFT JOIN $page\n". " ON page_title=cl_to\n". " WHERE\n". "   page_id IS NULL"; if ($this->debug) $wgOut->addWikiText("<"."pre>$sql<"."/pre>"); return $sql; } function getSQLCategoryLinks( $title = null ) { global $wgOut; $NScat = NS_CATEGORY; $dbr =& wfGetDB(DB_SLAVE); $categorylinks = $dbr->tableName('categorylinks'); $page         = $dbr->tableName('page'); $sql = "SELECT\n". "   page_title AS cat_from, \n". "   cl_to as cat_to,\n". "   page_is_redirect AS redirect\n". " FROM $page\n". " INNER JOIN $categorylinks\n". " ON page_id=cl_from\n". " WHERE\n". "   page_namespace={$NScat}"; if ($this->debug) $wgOut->addWikiText("<"."pre>$sql<"."/pre>"); return $sql; } function neighboursOnly{ return false ;} // This function is only needed for PHP prior to version 5. function file_put_contents($n,$d) { $f=@fopen($n,"wb"); if (!$f) { return false; }    else { fwrite($f,$d); fclose($f); return true; }   }    // This function is only needed for PHP prior to version 5. function file_get_contents($n) { $f=@fopen($n,"rb"); if (!$f) { return false; }    else { $s=filesize($n); $d=false; if ($s) $d=fread($f, $s) ; fclose($f); return $d; }   }      } class xyCategoryGraph extends xyCategoriesPage{ function neighboursOnly{ return true ;} function getSQLCategories( $title ) { global $wgOut; $id  = $title->getArticleID; $text = $title->getDBkey; $NScat = NS_CATEGORY; $dbr =& wfGetDB(DB_SLAVE); // Use the following for MediaWiki 1.9: // $text = $dbr->addQuotes($text); $text = "'".wfStrencode($text)."'"; $categorylinks = $dbr->tableName('categorylinks'); $page         = $dbr->tableName('page'); $sql = "SELECT DISTINCT\n". "   page_title AS cat,\n". "   page_is_redirect AS redirect,\n". "   0                AS virtual\n". " FROM $page as a\n". " left JOIN $categorylinks as b\n". " ON a.page_id=b.cl_from\n". " left join $categorylinks as c\n". " ON a.page_title=c.cl_to\n". " WHERE\n". "   page_namespace = {$NScat} AND\n". " (  c.cl_from    = $id OR\n".      "     a.page_id    = $id OR\n".      "     b.cl_to      = {$text} )\n"; if ($this->debug) $wgOut->addWikiText("<"."pre>$sql<"."/pre>"); return $sql; } function getSQLCategoryLinks( $title ) { global $wgOut; $id  = $title->getArticleID; $text = $title->getDBkey; $NScat = NS_CATEGORY; $dbr =& wfGetDB(DB_SLAVE); // Use the following for MediaWiki 1.9: // $text = $dbr->addQuotes($text); $text = "'".wfStrencode($text)."'"; $categorylinks = $dbr->tableName('categorylinks'); $page         = $dbr->tableName('page'); $sql = "SELECT\n". "   page_title AS cat_from, \n". "   cl_to as cat_to\n". " FROM $page\n". " INNER JOIN $categorylinks\n". " ON page_id=cl_from\n". " WHERE\n". "   ( page_id=$id  OR\n".      "    cl_to=$text ) AND\n". "   page_namespace={$NScat}"; if ($this->debug) $wgOut->addWikiText("<"."pre>$sql<"."/pre>"); return $sql; } }  function xyCategoryGraphHook($cat) { global $wgOut, $xyCategoriesMaxAge; $wgOut->setSquidMaxage( $xyCategoriesMaxAge ); $title = $cat->getTitle; $dbKey = $title->getDBkey; $cap = new xyCategoryGraph; $age = $cap->cacheAge($dbKey); if (!$age || $age > $xyCategoriesMaxAge ) { $cap->doQuery($title); $cap->doDot($dbKey); };   $cap->showImg($dbKey); return true; } ?>