68a8097a5b08f2dbeca97c48923fa254b45011ec
[atutor.git] / mods / wiki / plugins / feature / refererlog.php
1 <?php
2
3 /*
4    Inserts any REFERER url at the bottom of pages. Beforehand it validates
5    that the given URL isn't forged (can be accessed directly, and contains
6    an URL to the local resource - fuzzy matching). It uses the system
7    user name "RefererLog", but can also be made invisible in RecentChanges.
8    
9    @feature: refererlog
10    @depends: http, shutdown, patchsaving
11    @author: mario
12    @version: 1
13    @title: RefererLog
14    @desc: logs which pages link to it at the bottom of each page (validates existence of backlink)
15    @config: EWIKI_REFERER_NOISE=1 -- show discovered backlinks on RecentChanges
16 */
17
18 define("EWIKI_REFERER_NOISE", 2);
19
20
21 #-- activate I
22 if ($_SERVER["HTTP_REFERER"]) {
23    $ewiki_plugins["view_final"][] = "ewiki_view_referer_test";
24 }
25
26
27 #-- activate II
28 function ewiki_view_referer_test(&$o, $id, &$data, $action) {
29    global $ewiki_plugins;
30 #   if (!strpos($data["refs"], $_SERVER["HTTP_REFERER"]) && !strpos($_SERVER["HTTP_REFERER"], $_SERVER["SERVER_NAME"])) {
31 #      $ewiki_plugins["shutdown"][] = "ewiki_shutdown_referer_log";
32 #   }
33 ewiki_shutdown_referer_log($id, $data, $action);
34 }
35
36
37 #-- activate III
38 function ewiki_shutdown_referer_log($id, &$data, $action, $args=NULL) {
39    global $ewiki_config;
40    $iw = $ewiki_config["interwiki"];
41  
42    #-- the referer url
43    $ref = strtok($_SERVER["HTTP_REFERER"], "# ");
44    $this1 = EWIKI_SERVER . $_SERVER["REQUEST_URI"];
45    $this2 = ewiki_script("", $id);
46    
47    #-- pattern of ourselfs
48    $host = $_SERVER["HTTP_HOST"];
49    $pat = substr($host, strpos($host, ".") + 1);
50    if (!strpos($pat, ".")) {
51       $pat = $host;
52    }
53    
54
55    #-- reject if self-referring
56    if (strpos($ref, $host) || strpos($ref, $_SERVER["SERVER_NAME"])) {
57       return(false);
58    }
59    #-- reject search engine links
60    if (strpos($ref, "?") && strpos($ref, "q=")) {
61       return(false);
62    }
63
64    #-- link already on page?
65    $sref = trim($ref, "/");
66    $sref = substr($sref, strpos($sref, ".") + 1);
67    $sref = strtolower($sref);
68    if (strpos(strtolower($data["refs"]), $sref)) {
69       return(false);
70    }
71
72
73    #-- forgery test 1
74    if (strpos(urldecode($ref), $pat) || strpos(urldecode(urldecode($ref)), $pat)) {
75       ewiki_log("forged REFERER '$ref' to $this1");
76       return(-1);
77    }
78    #-- already banned?
79    if (function_exists("ewiki_banned_link") && ewiki_banned_link($ref)) {
80       ewiki_log("banned REFERER '$ref' to $this1");
81       return(-1);
82    }
83
84    #-- special cases
85    if (!strpos(trim(substr($ref, 10), "/"), "/")) {
86       $likely_fake = 1;  // link from server root dir?
87    }
88    elseif (strpos($ref, "slashdot")) {
89       $from_sd = 1;
90    }
91
92
93    #-- decode InterWiki URLs into "prefix:PageName" representation
94    if ($link = ewiki_url2wiki($ref)) {
95       if (stristr($data["refs"], $link)) {   // already in page
96          return(false);
97       }
98    }
99    else {
100       $link = $ref;
101    }
102    
103    
104    #-- retrieve page to check for link existence
105    $R = ewiki_http_query("GET", $ref, NULL, array(), "cookies.txt");
106    if (!stristr($R[0], $this1) && !stristr($R[0], $this2) && !(strpos($R[0], EWIKI_NAME.":$id"))) {
107       ewiki_log("faked REFERER '$ref' to $this1");
108       if ($likely_fake && ($abuse = $_SERVER["HTTP_FROM"])) {
109          mail(
110            $abuse,
111            "REFERER Header Abuse",
112            "Dear 'search-engine' maintainer,\n\nYou misused the HTTP Referer: header for marketing purposes.\nThis informational mail is meant to annoy you likewise.\n\n",
113            "X-From: $_SERVER[SERVER_ADMIN]\nX-Mailer: ewiki:refererlog\n"
114          );
115       }
116       return(-1);
117    }
118
119
120    #-- all tests passed, add link
121    $data = ewiki_db::GET($id);
122    if ($data["version"]++) {
123       $data["content"] = trim($data["content"])
124                        . "\n- $link\n";
125       ewiki_data_update($data);
126       $data["author"] = "RefererLog; " . $data["author"];
127       if (!EWIKI_REFERER_NOISE) {
128          $data["flags"] |= EWIKI_DB_F_MINOR;
129       }
130       ewiki_db::WRITE($data);
131    }
132
133 }
134
135
136 #-- decode URL to InterWiki link
137 function ewiki_url2wiki($url) {
138    global $ewiki_config;
139    foreach ($ewiki_config["interwiki"] as $moniker=>$s) {
140       if (strlen($s) <= 17) {
141          continue;
142       }
143       ($r = strpos($s, "?")) or ($r = strrpos($s, "/"));
144       $s = substr($s, 0, $r - 1);
145       if (strncmp($url, $s, strlen($s)) == 0) {
146          $page = substr($url, strlen($r));
147          preg_match("°(([".EWIKI_CHARS_U."]+[".EWIKI_CHARS_L."]+){2,}[\w\d]*)°", $page, $uu);
148          if ($page = $uu[1]) {
149             return("$moniker:$page");
150          }
151          return(false);
152       }
153    }
154 }
155
156
157 #-- simple HTTP requests
158 function ewiki_http_query($method, $url, $params=0, $req_headers=0, $cookies=0) {
159    $R = array(
160      0 => implode("", file($url))
161    );
162    return($R);
163 }
164
165
166 ?>