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.
10 @depends: http, shutdown, patchsaving
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
18 define("EWIKI_REFERER_NOISE", 2);
22 if ($_SERVER["HTTP_REFERER"]) {
23 $ewiki_plugins["view_final"][] = "ewiki_view_referer_test";
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";
33 ewiki_shutdown_referer_log($id, $data, $action);
38 function ewiki_shutdown_referer_log($id, &$data, $action, $args=NULL) {
40 $iw = $ewiki_config["interwiki"];
43 $ref = strtok($_SERVER["HTTP_REFERER"], "# ");
44 $this1 = EWIKI_SERVER . $_SERVER["REQUEST_URI"];
45 $this2 = ewiki_script("", $id);
47 #-- pattern of ourselfs
48 $host = $_SERVER["HTTP_HOST"];
49 $pat = substr($host, strpos($host, ".") + 1);
50 if (!strpos($pat, ".")) {
55 #-- reject if self-referring
56 if (strpos($ref, $host) || strpos($ref, $_SERVER["SERVER_NAME"])) {
59 #-- reject search engine links
60 if (strpos($ref, "?") && strpos($ref, "q=")) {
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)) {
74 if (strpos(urldecode($ref), $pat) || strpos(urldecode(urldecode($ref)), $pat)) {
75 ewiki_log("forged REFERER '$ref' to $this1");
79 if (function_exists("ewiki_banned_link") && ewiki_banned_link($ref)) {
80 ewiki_log("banned REFERER '$ref' to $this1");
85 if (!strpos(trim(substr($ref, 10), "/"), "/")) {
86 $likely_fake = 1; // link from server root dir?
88 elseif (strpos($ref, "slashdot")) {
93 #-- decode InterWiki URLs into "prefix:PageName" representation
94 if ($link = ewiki_url2wiki($ref)) {
95 if (stristr($data["refs"], $link)) { // already in page
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"])) {
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"
120 #-- all tests passed, add link
121 $data = ewiki_db::GET($id);
122 if ($data["version"]++) {
123 $data["content"] = trim($data["content"])
125 ewiki_data_update($data);
126 $data["author"] = "RefererLog; " . $data["author"];
127 if (!EWIKI_REFERER_NOISE) {
128 $data["flags"] |= EWIKI_DB_F_MINOR;
130 ewiki_db::WRITE($data);
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) {
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");
157 #-- simple HTTP requests
158 function ewiki_http_query($method, $url, $params=0, $req_headers=0, $cookies=0) {
160 0 => implode("", file($url))