• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cypht-org / cypht / 26230827274

21 May 2026 02:01PM UTC coverage: 72.803% (-5.4%) from 78.201%
26230827274

push

travis-ci

web-flow
Merge pull request #1972 from IrAlfred/remove-duplicate-testdox-flag-in-coverage-report

fix(workflow): remove duplicate --testdox flag causing coverage job exit code 1

4797 of 6589 relevant lines covered (72.8%)

7.74 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.73
/lib/dispatch.php
1
<?php
2

3
/**
4
 * Deal with redirects
5
 * @package framework
6
 * @subpackage dispatch
7
 */
8

9
trait Hm_Dispatch_Redirect {
10

11
    /**
12
     * Redirect after an HTTP POST form
13
     * @param Hm_Request $request request object
14
     * @param object $session session object
15
     * @param Hm_Module_Exec $mod_exec module manager object
16
     * @return boolean
17
     */
18
    private function post_redirect($request, $session, $mod_exec) {
6✔
19
        if (!empty($request->post) && $request->type == 'HTTP') {
6✔
20
            $this->forward_messages($session, $request);
1✔
21
            $session->end();
1✔
22
            $this->redirect_to_url($mod_exec);
1✔
23
            $this->redirect_to_current($request);
1✔
24
            return true;
1✔
25
        }
26
        return false;
6✔
27
    }
28

29
    /**
30
     * Redirect to the current url
31
     * @param Hm_Request $request
32
     * @return void
33
     */
34
    private function redirect_to_current($request) {
1✔
35
        if (array_key_exists('REQUEST_URI', $request->server)) {
1✔
36
            Hm_Dispatch::page_redirect($this->validate_request_uri($request->server['REQUEST_URI']));
1✔
37
        }
38
    }
39

40
    /**
41
     * Redirect to a specified url
42
     * @param object $mod_exec
43
     * @return void
44
     */
45
    private function redirect_to_url($mod_exec) {
1✔
46
        if (!empty($mod_exec->handler_response['redirect_url'])) {
1✔
47
            Hm_Dispatch::page_redirect($mod_exec->handler_response['redirect_url']);
1✔
48
        }
49
    }
50

51
    /**
52
     * Forward messages on a POST redirect
53
     * @param object $session session object
54
     * @return void
55
     */
56
    private function forward_messages($session, $request) {
1✔
57
        $msgs = Hm_Msgs::getRaw();
1✔
58
        if (!empty($msgs)) {
1✔
59
            $session->secure_cookie($request, 'hm_msgs', base64_encode(json_encode($msgs)));
1✔
60
        }
61
    }
62

63
    /**
64
     * Validate a request uri
65
     * @param string $uri URI to validate
66
     * @return string
67
     */
68
    public function validate_request_uri($uri) {
2✔
69
        $uri = html_entity_decode($uri);
2✔
70
        if ($uri === '') {
2✔
71
            return '/';
1✔
72
        }
73
        $parts = parse_url($uri);
2✔
74
        if (array_key_exists('scheme', $parts)) {
2✔
75
            return '/';
1✔
76
        }
77
        if ($parts === false || !array_key_exists('path', $parts) || mb_strpos($parts['path'], '..') !== false) {
2✔
78
            return '/';
1✔
79
        }
80
        return $uri;
2✔
81
    }
82

83

84
    /**
85
     * Redirect the page after a POST form is submitted and forward any user notices
86
     * @param Hm_Request $request request object
87
     * @param Hm_Module_Exec $mod_exec module manager object
88
     * @param object $session session object
89
     * @return string|false
90
     */
91
    public function check_for_redirect($request, $mod_exec, $session) {
6✔
92
        if (!empty($mod_exec->handler_response['no_redirect'])) {
6✔
93
            return 'noredirect';
1✔
94
        }
95
        if ($this->post_redirect($request, $session, $mod_exec)) {
6✔
96
            return 'redirect';
1✔
97
        } elseif (!empty($mod_exec->handler_response['redirect_url'])) {
6✔
98
            $session->end();
1✔
99
            $this->redirect_to_url($mod_exec);
1✔
100
            return 'redirect';
1✔
101
        } elseif ($this->unpack_messages($request, $session)) {
6✔
102
            return 'msg_forward';
×
103
        }
104
        return false;
6✔
105
    }
106

107
    /**
108
     * Unpack forwarded messages
109
     * @param Hm_Request $request request object
110
     * @param object $session session object
111
     * @return boolean
112
     */
113
    public function unpack_messages($request, $session) {
6✔
114
        if (!empty($request->cookie['hm_msgs'])) {
6✔
115
            $msgs = @json_decode(base64_decode($request->cookie['hm_msgs']), true);
×
116
            if (is_array($msgs)) {
×
117
                array_walk($msgs, function($v) { Hm_Msgs::add($v['text'], $v['type']); });
×
118
            }
119
            $session->delete_cookie($request, 'hm_msgs');
×
120
            return true;
×
121
        }
122
        return false;
6✔
123
    }
124

125
    /**
126
     * Perform an HTTP redirect
127
     * @param string $url url to redirect to
128
     * @param int $status current HTTP status
129
     * @return void
130
     */
131
    static public function page_redirect($url, $status = false) {
5✔
132
        if (DEBUG_MODE) {
5✔
133
            Hm_Debug::add(sprintf('Redirecting to %s', $url), 'info');
1✔
134
            Hm_Debug::load_page_stats();
1✔
135
            Hm_Debug::show();
1✔
136
        }
137
        if ($status == 303) {
5✔
138
            Hm_Debug::add('Redirect loop found', 'warning');
1✔
139
            Hm_Functions::cease('Redirect loop discovered');
1✔
140
        }
141
        Hm_Functions::header('HTTP/1.1 303 Found');
5✔
142
        Hm_Functions::header('Location: '.$url);
5✔
143
        Hm_Functions::cease();
5✔
144
    }
145

146
}
147

148
/**
149
 * Page request router that ties all the framework pieces together
150
 * @package framework
151
 * @subpackage dispatch
152
 */
153

154
class Hm_Dispatch {
155

156
    use Hm_Dispatch_Redirect;
157

158
    public $site_config;
159
    public $request;
160
    public $session;
161
    public $module_exec;
162
    public $page;
163
    public $output;
164

165
    /**
166
     * Setup object needed to process a request
167
     * @param object $config site configuration
168
     */
169
    public function __construct($config) {
6✔
170

171
        /* get the site config defined in the config/app.php file */
172
        $this->site_config = $config;
6✔
173

174
        /* check for the site module set override */
175
        $this->load_site_lib();
6✔
176

177
        /* setup a session handler, but don't actually start a session yet */
178
        $session_config = new Hm_Session_Setup($this->site_config);
6✔
179
        $this->session = $session_config->setup_session();
6✔
180

181
        /* instantiate the module runner */
182
        $this->module_exec = new Hm_Module_Exec($this->site_config);
6✔
183

184
        /* process request input using the white-lists defined in modules */
185
        $this->request = new Hm_Request($this->module_exec->filters, $config);
6✔
186

187
        /* do it */
188
        $this->process_request();
6✔
189
    }
190

191
    /**
192
     * Possibly include the site module lib.php overrides
193
     * @return void
194
     */
195
    private function load_site_lib() {
6✔
196
        if (!is_array($this->site_config->get_modules()) || !in_array('site', $this->site_config->get_modules(), true)) {
6✔
197
            return;
5✔
198
        }
199
        if (is_readable(APP_PATH.'modules/site/lib.php')) {
1✔
200
            Hm_Debug::add('Including site module set lib.php', 'info');
1✔
201
            require APP_PATH.'modules/site/lib.php';
1✔
202
        }
203
    }
204

205
    /**
206
     * Process a request
207
     * @return void
208
     */
209
    private function process_request() {
6✔
210

211
        /* get the request identifier */
212
        $this->get_page($this->module_exec->filters, $this->request);
6✔
213

214
        /* load up the module requirements */
215
        $this->module_exec->load_module_sets($this->page);
6✔
216

217
        /* run handler modules to process input and perform actions */
218
        $this->module_exec->run_handler_modules($this->request, $this->session, $this->page);
6✔
219

220
        /* clean up any network connections */
221
        $this->close_connections();
6✔
222

223
        /* check for update settings on login */
224
        $this->save_settings_on_login();
6✔
225

226
        /* check to see if a handler module told us to redirect the browser */
227
        $this->check_for_redirect($this->request, $this->module_exec, $this->session);
6✔
228

229
        /* save and close a session if one is open */
230
        $active_session = $this->save_session();
6✔
231

232
        /* run the output formatting modules */
233
        $this->module_exec->run_output_modules($this->request, $active_session, $this->page,
6✔
234
            $this->module_exec->handler_response);
6✔
235

236
        /* output content to the browser */
237
        $this->render_output();
6✔
238
    }
239

240
    /**
241
     * Check for a flag to save settings on login
242
     */
243
    private function save_settings_on_login() {
6✔
244
        if (!$this->session->loaded) {
6✔
245
            return;
6✔
246
        }
247
        try {
248
            if ($this->module_exec->user_config->save_on_login) {
×
249
                $this->module_exec->user_config->save($this->request->post['username'], $this->request->post['password']);
×
250
            }
251
        } catch (Exception $e) {
×
252
            Hm_Msgs::add('Could not save settings: ' . $e->getMessage(), 'warning');
×
253
        } 
254
    }
255

256
    /**
257
     * Close network connections if they exist
258
     * @return void
259
     */
260
    private function close_connections() {
6✔
261
        foreach (['Hm_IMAP_List', 'Hm_SMTP_List'] as $class) {
6✔
262
            if (Hm_Functions::class_exists($class)) {
6✔
263
                $class::clean_up();
1✔
264
            }
265
        }
266
    }
267

268
    /**
269
     * Close and save the session
270
     * @return bool true if the session is active
271
     */
272
    private function save_session() {
6✔
273
        $res = $this->session->is_active();
6✔
274
        $this->session->end();
6✔
275
        return $res;
6✔
276
    }
277

278
    /**
279
     * Format and send the request output to the browser
280
     * @return void
281
     */
282
    private function render_output() {
6✔
283
        $formatter = new $this->request->format($this->site_config);
6✔
284
        $class = $this->site_config->get('output_class', 'Hm_Output_HTTP');
6✔
285
        $renderer = new $class;
6✔
286
        $content = $formatter->content($this->module_exec->output_response, $this->request->allowed_output);
6✔
287
        /* TODO: might be a good idea to use a custom render class that can return
288
         * the output on demand */
289
        $this->output = $renderer->send_response($content, $this->module_exec->output_data);
6✔
290
    }
291

292
    /**
293
     * Get a list of valid pages
294
     * @param array $filters list of filters
295
     * @param return array
296
     */
297
    private function get_pages($filters) {
2✔
298
        return $filters['allowed_pages'] ?? [];
2✔
299
    }
300

301
    /**
302
     * Check for a valid ajax request
303
     * @param Hm_Request $request request details
304
     * @param array $filters list of filters
305
     * @return boolean
306
     */
307
    public function validate_ajax_request($request, $filters) {
2✔
308
        return $this->validate_hook($request->get, $filters) || $this->validate_hook($request->post, $filters);
2✔
309
    }
310

311
    /**
312
     * Validates ajax hook
313
     * @param array $input POST or GET data
314
     * @param array $filters list of filters
315
     * @return boolean
316
     */
317
    private function validate_hook($input, $filters) {
2✔
318
        if (array_key_exists('hm_ajax_hook', $input)) {
2✔
319
            if (in_array($input['hm_ajax_hook'], $this->get_pages($filters), true)) {
2✔
320
                return true;
1✔
321
            } else {
322
                Hm_Functions::cease(json_encode(['status' => 'not callable']));
1✔
323
            }
324
        }
325
        return false;
2✔
326
    }
327

328
    /**
329
     * Determine the page id
330
     * @param array $filters list of filters
331
     * @param Hm_Request $request request details
332
     * @return void
333
     */
334
    public function get_page($filters, $request) {
6✔
335
        $this->page = 'notfound';
6✔
336
        $page_param = $this->site_config->get('page_param_name');
6✔
337

338
        if ($request->type == 'AJAX' && $this->validate_ajax_request($request, $filters)) {
6✔
339
            $this->page = $request->get['hm_ajax_hook'] ?? $request->post['hm_ajax_hook'];
1✔
340
        } elseif (array_key_exists($page_param, $request->get) && in_array($request->get[$page_param], $this->get_pages($filters), true)) {
6✔
341
            $this->page = $request->get[$page_param];
×
342
        } elseif (!array_key_exists($page_param, $request->get)) {
6✔
343
            $this->page = 'home';
6✔
344
        }
345
        $this->module_exec->page = $this->page;
6✔
346
        Hm_Debug::add('Page ID: '.$this->page, 'info');
6✔
347
    }
348

349
    /**
350
     * Check to see if PHP is configured properly
351
     * @return bool
352
     */
353
    static public function is_php_setup() {
1✔
354
        return
1✔
355
            version_compare(PHP_VERSION, '7.4', '>=') &&
1✔
356
            Hm_Functions::function_exists('mb_strpos') &&
1✔
357
            Hm_Functions::function_exists('curl_exec') &&
1✔
358
            Hm_Functions::function_exists('openssl_random_pseudo_bytes') &&
1✔
359
            Hm_Functions::class_exists('PDO');
1✔
360
    }
361
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc