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
Contents |
[edit] same problem as above
Hi
I also have the same problem as described above. any solutions, plz?
Jack
[edit] 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:
- apt-get update /* updte avail packages */
- apt-get install graphviz /* install graphviz */
dot will be installed in /usr/bin/dot
[edit] 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';
[edit] 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
[edit] Example Please
Any examples of this extension?
[edit] 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.
[edit] The script
<?php
//Path to the GraphViz dot executable (Linux)
//$xyDotPath = "/usr/local/bin/dot";
//Path to the GraphViz dot executable (Windows)
$xyDotPath = "\"c:\\Programme\\Graphviz 2.21\\bin\\dot.exe\"";
$xyCategoriesMaxAge = 36;
// Path for the file cache relative to this script.
$xyCategoriesCache = "/images/xyGraphvizCache/";
if(!defined('MEDIAWIKI')){
// Serve the PNG image
$cap = new xyCategoryGraph();
if ($cap->serveFile()) die();
header("HTTP/1.1 404 Not Found");
die("<H1>404 Not Found </H1>");
}
//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("<IMG src=\"$URLpng\" usemap=\"#map1\" alt=\"$title\"><MAP name=\"map1\">$map</MAP>");
$wgOut->addWikiText(
wfMsg('xyrenderedwith')." [http://www.graphviz.org/ 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;
}
?>