1<?php if (!defined('PmWiki')) exit(); 2/* Copyright 2004-2021 Patrick R. Michaud (pmichaud@pobox.com) 3 This file is part of PmWiki; you can redistribute it and/or modify 4 it under the terms of the GNU General Public License as published 5 by the Free Software Foundation; either version 2 of the License, or 6 (at your option) any later version. See pmwiki.php for full details. 7 8 This script provides a URL-approval capability. To enable this 9 script, add the following line to a configuration file: 10 11 include_once('scripts/urlapprove.php'); 12 13 The URL prefixes to be allowed are stored as patterns in 14 $WhiteUrlPatterns. This array can be loaded from config.php, or 15 from the wiki pages given by the $ApprovedUrlPagesFmt[] array. 16 Any http: or https: URL that isn't in $WhiteUrlPatterns is rendered 17 using $UnapprovedLinkFmt. 18 19 The script also provides ?action=approveurls and ?action=approvesites, 20 which scan the current page for any new URLs to be automatically added 21 the first page of $UrlApprovalPagesFmt. 22 23 Finally, the script will block any post containing more than 24 $UnapprovedLinkCountMax unapproved urls in it. By default this 25 is set to a very large number, leaving the posting of unapproved 26 urls wide open, but by setting $UnapprovedLinkCountMax to a smaller 27 number you can limit the number of unapproved urls that make it into 28 a page. (Wikispammers seem to like to post long lists of urls, while 29 more "normal" authors tend to only post a few.) 30 31 Script maintained by Petko YOTOV www.pmwiki.org/petko 32*/ 33 34$LinkFunctions['http:'] = 'LinkHTTP'; 35$LinkFunctions['https:'] = 'LinkHTTP'; 36SDV($ApprovedUrlPagesFmt, array('$SiteAdminGroup.ApprovedUrls')); 37SDV($UnapprovedLinkFmt, 38 "\$LinkText<a class='apprlink' href='{\$PageUrl}?action=approvesites&\$TokenName=\$TokenValue'>$[(approve sites)]</a>"); 39SDVA($HTMLStylesFmt, array('urlapprove' => '.apprlink { font-size:smaller; }')); 40SDV($ApproveUrlPattern, 41 "\\bhttps?:[^\\s$UrlExcludeChars]*[^\\s.,?!$UrlExcludeChars]"); 42$WhiteUrlPatterns = (array)@$WhiteUrlPatterns; 43SDV($HandleActions['approveurls'], 'HandleApprove'); 44SDV($HandleAuth['approveurls'], 'edit'); 45SDV($HandleActions['approvesites'], 'HandleApprove'); 46SDV($HandleAuth['approvesites'], 'edit'); 47SDV($UnapprovedLinkCountMax, 1000000); 48array_splice($EditFunctions, array_search('PostPage', $EditFunctions), 49 0, 'BlockUnapprovedPosts'); 50 51function LinkHTTP($pagename,$imap,$path,$alt,$txt,$fmt=NULL) { 52 global $EnableUrlApprovalRequired, $IMap, $WhiteUrlPatterns, $FmtV, 53 $UnapprovedLink, $UnapprovedLinkCount, $UnapprovedLinkFmt; 54 if (!IsEnabled($EnableUrlApprovalRequired,1)) 55 return LinkIMap($pagename,$imap,$path,$alt,$txt,$fmt); 56 static $havereadpages; 57 if (!$havereadpages) { ReadApprovedUrls($pagename); $havereadpages=true; } 58 static $token; 59 if (!$token) $token = pmtoken(); 60 $FmtV['$TokenValue'] = urlencode($token); 61 62 $p = str_replace(' ','%20',$path); 63 $url = str_replace('$1',$p,$IMap[$imap]); 64 if (!isset($UnapprovedLink)) $UnapprovedLink = array(); 65 foreach((array)$WhiteUrlPatterns as $pat) { 66 if (preg_match("!^$pat(/|$)!i",$url)) 67 return LinkIMap($pagename,$imap,$path,$alt,$txt,$fmt); 68 } 69 $FmtV['$LinkUrl'] = PUE(str_replace('$1',$path,$IMap[$imap])); 70 $FmtV['$LinkText'] = $txt; 71 $FmtV['$LinkAlt'] = str_replace(array('"',"'"),array('"','''),$alt); 72 $UnapprovedLink[] = $url; 73 @$UnapprovedLinkCount++; 74 return FmtPageName($UnapprovedLinkFmt,$pagename); 75} 76 77function ReadApprovedUrls($pagename) { 78 global $ApprovedUrlPagesFmt,$ApproveUrlPattern,$WhiteUrlPatterns; 79 foreach((array)$ApprovedUrlPagesFmt as $p) { 80 $pn = FmtPageName($p, $pagename); 81 StopWatch("ReadApprovedUrls $pn begin"); 82 $apage = ReadPage($pn, READPAGE_CURRENT); 83 preg_match_all("/$ApproveUrlPattern/",@$apage['text'],$match); 84 foreach($match[0] as $a) 85 $WhiteUrlPatterns[] = preg_quote($a,'!'); 86 StopWatch("ReadApprovedUrls $pn end"); 87 } 88} 89 90function HandleApprove($pagename, $auth='edit') { 91 global $ApproveUrlPattern,$WhiteUrlPatterns,$ApprovedUrlPagesFmt,$action; 92 Lock(2); 93 $page = ReadPage($pagename); 94 $text = preg_replace('/[()]/','',$page['text']); 95 preg_match_all("/$ApproveUrlPattern/",$text,$match); 96 ReadApprovedUrls($pagename); 97 $addpat = array(); 98 foreach($match[0] as $a) { 99 if ($action=='approvesites') 100 $a=preg_replace("!^([^:]+://[^/]+).*$!",'$1',$a); 101 $addpat[] = $a; 102 } 103 if (count($addpat)>0) { 104 $aname = FmtPageName($ApprovedUrlPagesFmt[0],$pagename); 105 $apage = RetrieveAuthPage($aname, $auth); 106 if (!$apage) Abort("?cannot edit $aname"); 107 if(! AutoCheckToken()) { 108 Abort('? $[Token invalid or missing.]'); 109 } 110 $new = $apage; 111 if (substr($new['text'],-1,1)!="\n") $new['text'].="\n"; 112 foreach($addpat as $a) { 113 foreach((array)$WhiteUrlPatterns as $pat) 114 if (preg_match("!^$pat(/|$)!i",$a)) continue 2; 115 $urlp = preg_quote($a,'!'); 116 $WhiteUrlPatterns[] = $urlp; 117 $new['text'].=" $a\n"; 118 } 119 $_POST['post'] = 'y'; 120 PostPage($aname,$apage,$new); 121 } 122 Redirect($pagename); 123} 124 125function BlockUnapprovedPosts($pagename, &$page, &$new) { 126 global $EnableUrlApprovalRequired, $UnapprovedLinkCount, 127 $UnapprovedLinkCountMax, $EnablePost, $MessagesFmt, $BlockMessageFmt; 128 if (!IsEnabled($EnableUrlApprovalRequired, 1)) return; 129 if ($UnapprovedLinkCount <= $UnapprovedLinkCountMax) return; 130 if ($page['=auth']['admin']) return; 131 $EnablePost = 0; 132 $MessagesFmt[] = $BlockMessageFmt; 133 $MessagesFmt[] = XL('Too many unapproved external links.'); 134} 135 136