backlinkage.pl 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. # Copyright (C) 2006 Charles Mauch <cmauch@gmail.com>
  2. #
  3. # This program is free software; you can redistribute it and/or modify
  4. # it under the terms of the GNU General Public License as published by
  5. # the Free Software Foundation; either version 2 of the License, or
  6. # (at your option) any later version.
  7. #
  8. # This program is distributed in the hope that it will be useful,
  9. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. # GNU General Public License for more details.
  12. #
  13. # You should have received a copy of the GNU General Public License
  14. # along with this program; if not, write to the
  15. # Free Software Foundation, Inc.
  16. # 59 Temple Place, Suite 330
  17. # Boston, MA 02111-1307 USA
  18. # Grab MLDBM at http://search.cpan.org/dist/MLDBM/lib/MLDBM.pm
  19. # ie: http://search.cpan.org/CPAN/authors/id/C/CH/CHAMAS/MLDBM-2.01.tar.gz
  20. use strict;
  21. use v5.10;
  22. use Fcntl;
  23. use MLDBM qw( DB_File Storable );
  24. AddModuleDescription('backlinkage.pl', 'Inline Backlinks');
  25. our ($q, %Action, %Page, @MyAdminCode, $DataDir, $LinkPattern);
  26. my $debug=1; # Set Text Output Verbosity when compiling
  27. my $backfile = $DataDir . '/backlinks.db'; # Where data lives
  28. # Stuff buildback action into admin menu.
  29. push(@MyAdminCode, \&BacklinksMenu);
  30. sub BacklinksMenu {
  31. my ($id, $menuref, $restref) = @_;
  32. push(@$menuref,
  33. ScriptLink('action=buildback', T('Rebuild BackLink database'))
  34. );
  35. }
  36. # Build Database, called my oddmuse uri action
  37. $Action{buildback} = \&BuildBacklinkDatabase;
  38. sub BuildBacklinkDatabase {
  39. print GetHttpHeader('text/plain');
  40. Unlink($backfile); # Remove old database
  41. tie my %backhash, 'MLDBM', encode_utf8($backfile) or die "Cannot open file $backfile $!\n";
  42. log1("Starting Database Store Process ... please wait\n\n");
  43. foreach my $name (AllPagesList()) {
  44. log3("Opening $name ... \n");
  45. OpenPage($name);
  46. my @backlinks = BacklinkProcess($name,$Page{text});
  47. my $hash = $backhash{$name}; # Declare Hash Ref
  48. my $backlinkcount = 0; # Used to create link key
  49. foreach my $link (@backlinks) {
  50. $backlinkcount++;
  51. $hash->{'link' . $backlinkcount} = $link;
  52. }
  53. log2("$backlinkcount Links found in $name\n") if $backlinkcount;
  54. $backhash{$name} = $hash; # Store Hash data in HoH
  55. }
  56. if ($debug >= 3) {
  57. log4("Printing dump of USABLE Data we stored, sorted and neat\n");
  58. for my $source (sort keys %backhash) {
  59. for my $role (sort keys %{ $backhash{$source} }) {
  60. log4("\n\$HoH\{\'$source\'\}\{\'$role\'\} = \"$backhash{$source}{$role}\"");
  61. }
  62. }
  63. }
  64. untie %backhash;
  65. log1("Done. \n");
  66. }
  67. # Used to filter though page text to find links, ensure there is only 1 link per destination
  68. # per page, and then return an array of backlinks.
  69. sub BacklinkProcess {
  70. my $name = $_[0];
  71. my $text = $_[1];
  72. my %seen = ();
  73. my @backlinks;
  74. my @wikilinks = ($text =~ m/$LinkPattern/g);
  75. foreach my $links (@wikilinks) {
  76. my ($class, $resolved, $title, $exists) = ResolveId($links);
  77. if ($exists) {
  78. push (@backlinks,$resolved) unless (($seen{$resolved}++) or ($resolved eq $name));
  79. }
  80. }
  81. return @backlinks;
  82. }
  83. # Function used by user to display backlinks in proper html.
  84. sub GetBackLink {
  85. my (@backlinks, @unpopped, @alldone);
  86. my $id = $_[0];
  87. our ($BacklinkBanned);
  88. $BacklinkBanned = "HomePage|ScratchPad" if !$BacklinkBanned;
  89. tie my %backhash, 'MLDBM', encode_utf8($backfile), O_CREAT|O_RDWR, oct(644) or die "Cannot open file $backfile $!\n";
  90. # Search database for matches
  91. while ( my ($source, $hashes) = each %backhash ) {
  92. while ( my ($key, $value) = each %$hashes ) {
  93. if ($id =~ /$value/) {
  94. push (@backlinks, $source);
  95. }
  96. }
  97. }
  98. untie %backhash;
  99. # Render backlinks into html links
  100. foreach my $backlink (@backlinks) {
  101. my ($class, $resolved, $title, $exists) = ResolveId($backlink);
  102. if (($resolved ne $id) && ($resolved !~ /^($BacklinkBanned)$/)) {
  103. push(@unpopped, ScriptLink(UrlEncode($resolved), $resolved, $class . ' backlink', undef, Ts('Internal Page: %s', $resolved)));
  104. }
  105. }
  106. my $arraycount = @unpopped;
  107. return if !$arraycount; # Dont bother with the rest if empty results
  108. # Pop and Push data to make it look good (no trailing commas)
  109. my $temp = pop(@unpopped);
  110. foreach my $backlink (@unpopped) {
  111. push(@alldone, $backlink . ", ");
  112. }
  113. push(@alldone, $temp); # And push last entry back in
  114. print $q->div({-class=>'docmeta'}, $q->h2(T('Pages that link to this page')), @alldone);
  115. }
  116. # Debug functions, all expect a string as input, and print it if the debug level is high enough.
  117. # This allows for increasing levels of verbosity for runtime commenting.
  118. sub log1 { # Very little info (only outputs if error - great for scripts)
  119. return if (($debug < 1) or ($debug == 4));
  120. my $msg = shift;
  121. print "$msg";
  122. }
  123. sub log2 { # Info Messages
  124. return if (($debug < 2) or ($debug == 4));
  125. my $msg = shift;
  126. print "$msg";
  127. }
  128. sub log3 { # More Info for the curious
  129. return if (($debug < 3) or ($debug == 4));
  130. my $msg = shift;
  131. print "$msg";
  132. }
  133. sub log4 { # Dump all sorts of garbage (usally data structures)
  134. return if ($debug < 4);
  135. my $msg = shift;
  136. print "$msg";
  137. }