1<?php
2/**
3 * NoHighlight Plugin for DokuWiki / action.php
4 *
5 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
6 * @author  Kazutaka Miyasaka <kazmiya@gmail.com>
7 */
8
9// must be run within DokuWiki
10if (!defined('DOKU_INC')) {
11    die();
12}
13
14if (!defined('DOKU_PLUGIN')) {
15    define('DOKU_PLUGIN', DOKU_INC . 'lib/plugins/');
16}
17
18require_once DOKU_PLUGIN . 'action.php';
19
20class action_plugin_nohighlight extends DokuWiki_Action_Plugin
21{
22    /**
23     * Stores original array of highlight candidates
24     */
25    var $highlight_orig = array();
26
27    /**
28     * Configurations (may be overridden)
29     */
30    var $disable_highlight = 'all';
31    var $remove_url_params = 1;
32
33    /**
34     * Registers event handlers
35     */
36    function register(&$controller)
37    {
38        $controller->register_hook(
39            'DOKUWIKI_STARTED', 'BEFORE',
40            $this, 'disableHighlight', array()
41        );
42
43        $controller->register_hook(
44            'DOKUWIKI_STARTED', 'AFTER',
45            $this, 'removeUrlParams', array('do' => 'get')
46        );
47
48        $controller->register_hook(
49            'SEARCH_QUERY_FULLPAGE', 'AFTER',
50            $this, 'removeUrlParams', array('do' => 'modify')
51        );
52
53        $controller->register_hook(
54            'FULLTEXT_SNIPPET_CREATE', 'BEFORE',
55            $this, 'removeUrlParams', array('do' => 'restore')
56        );
57    }
58
59    /**
60     * Disables search term highlighting
61     */
62    function disableHighlight(&$event, $param)
63    {
64        global $HIGH;
65        global $ACT;
66
67        if ($ACT !== 'show' && $ACT !== 'search') {
68            return;
69        }
70
71        $this->setConfig();
72
73        switch ($this->disable_highlight) {
74            case 'none':
75                return;
76
77            // disable all highlighting features
78            case 'all':
79                $HIGH = '';
80                break;
81
82            // disable highlighting by URL param ?s[]=term
83            case 'query':
84                if (!empty($_REQUEST['s'])) {
85                    $HIGH = '';
86                }
87                break;
88
89            // disable auto-highlight via search engines
90            case 'auto':
91                $HIGH = isset($_REQUEST['s']) ? (string) $_REQUEST['s'] : '';
92                break;
93        }
94    }
95
96    /**
97     * Sets per-user or site-wide configurations
98     */
99    function setConfig()
100    {
101        @session_start();
102
103        if (isset($_REQUEST['nohighlight'])) {
104            if ($_REQUEST['nohighlight']) {
105                $_SESSION[DOKU_COOKIE]['nohighlight'] = 1;
106            } else {
107                unset($_SESSION[DOKU_COOKIE]['nohighlight']);
108            }
109        }
110
111        if ($_SESSION[DOKU_COOKIE]['nohighlight']) {
112            // set per-user config (disable all features only)
113            $this->disable_highlight = 'all';
114            $this->remove_url_params = 1;
115        } else {
116            // set site-default config
117            $this->disable_highlight = $this->getConf('disable_highlight');
118            $this->remove_url_params = $this->getConf('remove_url_params');
119        }
120    }
121
122    /**
123     * Manipulates highlight terms to remove ?s[]=term from search result URLs
124     */
125    function removeUrlParams(&$event, $param)
126    {
127        if (!$this->remove_url_params) {
128            return;
129        }
130
131        switch ($param['do']) {
132            case 'get':
133                $this->getCandidatesFromReferer();
134                break;
135
136            case 'modify':
137                $this->modifyCandidates($event->data['highlight']);
138                break;
139
140            case 'restore':
141                $this->restoreCandidates($event->data['highlight']);
142                break;
143        }
144    }
145
146    /**
147     * Gets highlight candidates from HTTP_REFERER info
148     * (A compensation for "remove_url_params" option)
149     */
150    function getCandidatesFromReferer()
151    {
152        global $HIGH;
153        global $ACT;
154
155        if (
156            $ACT !== 'show' ||
157            !empty($HIGH) ||
158            !isset($_SERVER['HTTP_REFERER']) ||
159            in_array($this->disable_highlight, array('all', 'auto'))
160        ) {
161            return;
162        }
163
164        $referer = (string) $_SERVER['HTTP_REFERER'];
165
166        if (
167            strpos($referer, DOKU_URL) === 0 &&
168            preg_match('/[?&]do=search&id=([^&]+)/', $referer, $matches)
169        ) {
170            // users seem to have jumped from search result link in this wiki
171            require_once DOKU_INC . 'inc/fulltext.php';
172
173            $query = urldecode($matches[1]);
174
175            // set highlight candidates
176            // (ft_queryParser has been modified since DokuWiki Rincewind)
177            if (function_exists('idx_get_indexer')) {
178                $Indexer = idx_get_indexer();
179                $parsed_query = ft_queryParser($Indexer, $query);
180            } else {
181                $parsed_query = ft_queryParser($query);
182            }
183
184            $HIGH = $parsed_query['highlight'];
185        }
186    }
187
188    /**
189     * Modifies highlight candidates
190     */
191    function modifyCandidates(&$highlight)
192    {
193        $functions = array();
194
195        foreach (debug_backtrace() as $trace) {
196            $functions[] = $trace['function'];
197        }
198
199        // hack if called via html_search()
200        if (in_array('html_search', $functions)) {
201            $this->highlight_orig = $highlight;
202            $highlight = array();
203        } else {
204            $this->highlight_orig = array();
205        }
206    }
207
208    /**
209     * Restores highlight candidates
210     */
211    function restoreCandidates(&$highlight)
212    {
213        // snippet creation with no highlight term causes heavy load
214        if (!empty($this->highlight_orig)) {
215            $highlight = $this->highlight_orig;
216        }
217    }
218}
219