1<?php
2
3use dokuwiki\Extension\AuthPlugin;
4use dokuwiki\HTTP\DokuHTTPClient;
5use dokuwiki\Extension\Event;
6require_once __DIR__.'/helperfunctions.php';
7
8
9class helper_plugin_linkcheck extends Dokuwiki_Plugin
10{
11    private $dbfile=null; #use getdbfile() to access this.
12    private $db=null;  #use getdb() to access this.
13    private $cacheexpirytime=null; #use getcacheexpirytime() to access this.
14    private $cacertfile=null; #use getcacertfile(). a file is only set if the autodownloadcacert is ON.
15    private $cacertfileexpirytime=null; #use getcacertfileexpirytime() to access this.
16    private $usecache=null; #use usecache() to access this.
17
18    public function __construct(){
19        $this->usecache = $this->getConf('usecache');
20        if($this->usecache && !class_exists('SQLite3',false)){
21            msg('linkcheck:usecache option is enabled but SQLite3 is not available. Disabling cache...');
22            $this->usecache=false;
23        }
24    }
25    function getusecache(){
26        return $this->usecache;
27    }
28    function getdbfile(){
29        if(!isset($this->dbfile)){
30            if($this->getusecache())  $this->dbfile = metaFN('linkcheck_cache','.sqlite');
31            else $this->dbfile=false;
32        }
33        return $this->dbfile;
34    }
35    function getcacertfile(){
36        if(!isset($this->cacertfile)){
37            if($this->getConf('autodownloadcacert'))  $this->cacertfile = metaFN('linkcheck_cacert','.pem');
38            else $this->cacertfile=false;
39        }
40        return $this->cacertfile;
41    }
42    function getcacertfileexpirytime(){
43        if(!isset($this->cacertfileexpirytime)){
44            $this->cacertfileexpirytime=expiry_totime($this->getConf('cacertfileexpiry'));
45        }
46        return $this->cacertfileexpirytime;
47    }
48
49    function &getdb(){
50        if(!isset($this->db)){
51            if($file=$this->getdbfile()) $this->db=linkcheck_db($file);
52            else $this->db=false;
53        }
54        return $this->db;
55    }
56    function getcacheexpirytime(){
57        if(!isset($this->cacheexpirytime)){
58            $this->cacheexpirytime=expiry_totime($this->getConf('cacheexpiry'));
59        }
60        return $this->cacheexpirytime;
61    }
62    function checkurl($url){
63        if($this->getusecache()){
64            $o=[
65                'dbfile'=>$this->getdbfile(),
66                'cacheexpirytime'=>$this->getcacheexpirytime(),
67                'requireexists'=>$this->getConf('requireexists'),
68                'cacertfile'=>$this->getcacertfile(),
69                'cacertfileexpirytime'=>$this->getcacertfileexpirytime(),
70            ];
71            return linkcheck_checkurl_withcache($url,$o);
72        }
73        else{
74            $o=[
75                'cacertfile'=>$this->getcacertfile(),
76                'cacertfileexpirytime'=>$this->getcacertfileexpirytime(),
77            ];
78            return linkcheck_checkurl($url,$o);
79
80        }
81    }
82    function getcachedata($id,$urls){
83        $db=&$this->getdb();
84        $urlmap=[];
85
86        #first query: more efficient: get all urls with pages=$id
87        $id_=$db->escapeString($id);
88        $query="SELECT url,codegroup,lastcheck FROM linkcheck_cache WHERE pages='$id_' OR pages LIKE '$id_,%' OR pages LIKE '%,$id_' OR pages LIKE '%,$id_,%'";
89        foreach(linkcheck_db_query($db,$query) as $row){
90            $url=$row['url']; unset($row['url']);
91            $urlmap[$url]=$row;
92        }
93
94        #delete any pageurls that no longer appear for $id
95        if($deleteurls = array_diff(array_keys($urlmap),$urls)){
96            #msg("Deleting urls: ".implode(',',$deleteurls));
97            $urls_=array_map([$db,'escapeString'],$deleteurls);
98            $urls_=array_map(function($url){return "'$url'";},$urls_);
99            #delete the urls that are only for this page.
100            $query="DELETE FROM linkcheck_cache WHERE pages='$id_' AND url IN (".implode(',',$urls_).")";
101            $db->exec($query);
102
103            #for urls that are shared with other pages, just empty the pages value (for efficiency, we won't try to individually remove id from each of these rows).
104            $query="UPDATE linkcheck_cache SET pages='' WHERE url IN (".implode(',',$urls_).")";
105            $db->exec($query);
106        }
107
108        #second query: get remaining urls that have previously not been registered for this $id.
109        if($newurls=array_diff($urls,array_keys($urlmap))){
110            $urls_=array_map([$db,'escapeString'],$newurls);
111            $urls_=array_map(function($url){return "'$url'";},$urls_);
112            $query="SELECT url,codegroup,lastcheck,pages FROM linkcheck_cache WHERE url IN (".implode(',',$urls_).")";
113            foreach(linkcheck_db_query($db,$query) as $row){
114                $url=$row['url']; unset($row['url']);
115                $urlmap[$url]=$row;
116            }
117        }
118
119        if(!$newurls){
120            #msg("No new urls to insert or update.");
121            return $urlmap;
122        }
123        #insert urls that are not in the cache. update pages if the current $id not in pages column.
124        #insert should be enough, but to account for simultaneous requests, we keep "ignore into"
125        $insertstmt = $db->prepare("INSERT OR IGNORE INTO linkcheck_cache(url,pages) VALUES (:url,:pages)");
126        $updatestmt = $db->prepare("UPDATE linkcheck_cache SET pages=:pages WHERE url=:url");
127        foreach($newurls as $url){
128            if(!isset($urlmap[$url])){
129                #msg("Inserting new url [ $url ] for page [ $id ]...");
130                $insertstmt->bindValue(':url', $url, SQLITE3_TEXT);
131                $insertstmt->bindValue(':pages',$id, SQLITE3_TEXT);
132                $insertstmt->execute();
133            }
134            #elseif($urlmap[$url]['pages']!=$id && !in_array($id,explode(',',$urlmap[$url]['pages']))){
135            else{
136                #msg("Registering existing url [ $url ] for page [ $id ]...");
137                $updatestmt->bindValue(':url', $url, SQLITE3_TEXT);
138                $updatestmt->bindValue(':pages', $urlmap[$url]['pages'].','.$id, SQLITE3_TEXT);
139                $updatestmt->execute();
140            }
141        }
142        return $urlmap;
143    }
144}
145