Issues (2)

Security Analysis    no request data  

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/ViewService.php (2 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace mindplay\kisstpl;
4
5
use Closure;
6
use Exception;
7
use RuntimeException;
8
use Throwable;
9
10
/**
11
 * This service provides a view/template rendering service and a simple output capture facility.
12
 */
13
class ViewService implements Renderer
14
{
15
    /**
16
     * @var ViewFinder
17
     */
18
    public $finder;
19
20
    /**
21
     * @var string the default type of view
22
     *
23
     * @see render()
24
     */
25
    public $default_type = 'view';
26
27
    /**
28
     * @var string[] a stack of variable references being captured to
29
     *
30
     * @see begin()
31
     * @see end()
32
     */
33
    protected $capture_stack = array();
34
35
    /**
36
     * @var int a unique index to track use of the capture stack
37
     *
38
     * @see begin()
39
     * @see end()
40
     */
41
    private $capture_index = 0;
42
43
    /**
44
     * @var string[][] map where view-model class name => map where view type => view path
45
     */
46
    private $path_cache = array();
47
48
    /**
49
     * @var Closure[] map where view path => view Closure
50
     */
51
    private $closure_cache = array();
52
53
    /**
54
     * @param ViewFinder $finder
55
     */
56 1
    public function __construct(ViewFinder $finder)
57
    {
58 1
        $this->finder = $finder;
59 1
    }
60
61
    /**
62
     * Locate and render a PHP template for the given view, directly to output - as
63
     * opposed to {@see capture()} which will use output buffering to capture the
64
     * content and return it as a string.
65
     *
66
     * The view will be made available to the template as <code>$view</code> and the
67
     * calling context (<code>$this</code>) will be this ViewService.
68
     *
69
     * @param object      $view the view-model to render
70
     * @param string|null $type the type of view to render (optional)
71
     *
72
     * @return void
73
     *
74
     * @throws RuntimeException
75
     *
76
     * @see capture()
77
     */
78 1
    public function render($view, $type = null)
79
    {
80 1
        $__type = $type === null
81 1
            ? $this->default_type
82 1
            : $type;
83
84 1
        unset($type);
85
86 1
        $__class = get_class($view);
87
88 1
        if (! isset($this->path_cache[$__class][$__type])) {
89 1
            $this->path_cache[$__class][$__type] = $this->finder->findTemplate($view, $__type);
90
        }
91
92 1
        $__path = $this->path_cache[$__class][$__type];
93
94 1
        if ($__path === null) {
95 1
            $this->onMissingView($view, $__type);
96
97 1
            return;
98
        }
99
100 1
        $__depth = count($this->capture_stack);
101
102 1
        $ob_level = ob_get_level();
103
104 1
        $this->renderFile($__path, $view);
105
106 1
        if (ob_get_level() !== $ob_level) {
107 1
            $error = count($this->capture_stack) !== $__depth
108 1
                ? "begin() without matching end()"
109 1
                : "output buffer-level mismatch: was " . ob_get_level() . ", expected {$ob_level}";
110
111 1
            while (ob_get_level() > $ob_level) {
112 1
                ob_end_clean(); // clean up any hanging output buffers prior to throwing
113
            }
114
115 1
            throw new RuntimeException("{$error} in file: {$__path}");
116
        }
117 1
    }
118
119
    /**
120
     * Render and capture the output from a PHP template for the given view - as
121
     * opposed to {@see render()} which will render directly to output.
122
     *
123
     * Use capture only when necessary, such as when capturing content from a
124
     * rendered template to populate the body of an e-mail.
125
     *
126
     * @param object      $view the view-model to render
127
     * @param string|null $type the type of view to render (optional)
128
     *
129
     * @return string rendered content
130
     *
131
     * @see render()
132
     */
133 1
    public function capture($view, $type = null)
134
    {
135 1
        ob_start();
136
137
        try {
138 1
            $this->render($view, $type);
139 1
        } catch (Exception $exception) {
140
            // re-throwing below (PHP 5.3+)
141
        } catch (Throwable $exception) {
0 ignored issues
show
The class Throwable does not exist. Is this class maybe located in a folder that is not analyzed, or in a newer version of your dependencies than listed in your composer.lock/composer.json?
Loading history...
142
            // re-throwing below (PHP 7.0+)
143
        }
144
145 1
        $output = ob_get_clean();
146
147 1
        if (isset($exception)) {
148 1
            throw $exception;
149
        }
150
151 1
        return $output;
152
    }
153
154
    /**
155
     * @param string &$var target variable reference for captured content
156
     *
157
     * @return void
158
     *
159
     * @see end()
160
     */
161 1
    public function begin(&$var)
162
    {
163 1
        $index = $this->capture_index++;
164
165 1
        $var = __CLASS__ . "::\$capture_stack[{$index}]";
166
167 1
        if (in_array($var, $this->capture_stack, true)) {
168 1
            throw new RuntimeException("begin() with same reference as prior begin()");
169
        }
170
171 1
        $this->capture_stack[] = &$var;
172
173
        // begin buffering content to capture:
174 1
        ob_start();
175 1
    }
176
177
    /**
178
     * @param string &$var target variable reference for captured content
179
     *
180
     * @return void
181
     *
182
     * @throws RuntimeException
183
     *
184
     * @see begin()
185
     */
186 1
    public function end(&$var)
187
    {
188 1
        if (count($this->capture_stack) === 0) {
189 1
            throw new RuntimeException("end() without begin()");
190
        }
191
192 1
        $index = count($this->capture_stack) - 1;
193
194 1
        if ($this->capture_stack[$index] !== $var) {
195 1
            throw new RuntimeException("end() with mismatched begin()");
196
        }
197
198
        // capture the buffered content:
199 1
        $this->capture_stack[$index] = ob_get_clean();
200
201
        // remove target variable reference from stack:
202 1
        array_pop($this->capture_stack);
203 1
    }
204
205
    /**
206
     * Internally render a template file (or delegate to a cached closure)
207
     *
208
     * @param string $_path_ absolute path to PHP template
209
     * @param object $view the view-model to render
210
     *
211
     * @return void
212
     */
213 1
    protected function renderFile($_path_, $view)
214
    {
215 1
        if (!isset($this->closure_cache[$_path_])) {
216 1
            $_closure_ = require $_path_;
217
218 1
            if (is_callable($_closure_)) {
219 1
                $this->closure_cache[$_path_] = $_closure_;
220
            }
221
        }
222
223 1
        if (isset($this->closure_cache[$_path_])) {
224 1
            $this->renderClosure($this->closure_cache[$_path_], $view);
0 ignored issues
show
$this->closure_cache[$_path_] is of type callable, but the function expects a object<Closure>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
225
        }
226 1
    }
227
228
    /**
229
     * Internally render a template closure
230
     *
231
     * @param Closure $closure template closure
232
     * @param object  $view    the view-model to render
233
     *
234
     * @return void
235
     */
236 1
    protected function renderClosure($closure, $view)
237
    {
238 1
        call_user_func($closure, $view, $this);
239 1
    }
240
241
    /**
242
     * Called internally, if a view could not be resolved
243
     *
244
     * @param object      $view the view-model attempted to render
245
     * @param string|null $type the type of view attempted to render (optional)
246
     *
247
     * @return void
248
     *
249
     * @see render()
250
     */
251 1
    protected function onMissingView($view, $type)
252
    {
253 1
        $class = get_class($view);
254
255 1
        $paths = $this->finder->listSearchPaths($view, $type);
256
257 1
        $message = count($paths) > 0
258 1
            ? "searched paths:\n  * " . implode("\n  * ", $paths)
259 1
            : "no applicable path(s) found";
260
261 1
        throw new RuntimeException("no view of type \"{$type}\" found for model: {$class} - {$message}");
262
    }
263
}
264