Issues (292)

Security Analysis    not enabled

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.

lib/Dwoo/Template/Str.php (3 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
 * Copyright (c) 2013-2017
4
 *
5
 * @category  Library
6
 * @package   Dwoo\Template
7
 * @author    Jordi Boggiano <[email protected]>
8
 * @author    David Sanchez <[email protected]>
9
 * @copyright 2008-2013 Jordi Boggiano
10
 * @copyright 2013-2017 David Sanchez
11
 * @license   http://dwoo.org/LICENSE LGPLv3
12
 * @version   1.4.0
13
 * @date      2017-03-16
14
 * @link      http://dwoo.org/
15
 */
16
17
namespace Dwoo\Template;
18
19
use Dwoo\Core;
20
use Dwoo\Compiler;
21
use Dwoo\ITemplate;
22
use Dwoo\ICompiler;
23
use Dwoo\Exception;
24
25
/**
26
 * Represents a Dwoo template contained in a string.
27
 * This software is provided 'as-is', without any express or implied warranty.
28
 * In no event will the authors be held liable for any damages arising from the use of this software.
29
 */
30
class Str implements ITemplate
31
{
32
    /**
33
     * Template name.
34
     *
35
     * @var string
36
     */
37
    protected $name;
38
39
    /**
40
     * Template compilation id.
41
     *
42
     * @var string
43
     */
44
    protected $compileId;
45
46
    /**
47
     * Template cache id, if not provided in the constructor, it is set to
48
     * the md4 hash of the request_uri. it is however highly recommended to
49
     * provide one that will fit your needs.
50
     * in all cases, the compilation id is prepended to the cache id to separate
51
     * templates with similar cache ids from one another
52
     *
53
     * @var string
54
     */
55
    protected $cacheId;
56
57
    /**
58
     * Validity duration of the generated cache file (in seconds).
59
     * set to -1 for infinite cache, 0 to disable and null to inherit the Dwoo instance's cache time
60
     *
61
     * @var int
62
     */
63
    protected $cacheTime;
64
65
    /**
66
     * Boolean flag that defines whether the compilation should be enforced (once) or
67
     * not use this if you have issues with the compiled templates not being updated
68
     * but if you do need this it's most likely that you should file a bug report.
69
     *
70
     * @var bool
71
     */
72
    protected $compilationEnforced;
73
74
    /**
75
     * Caches the results of the file checks to save some time when the same
76
     * templates is rendered several times.
77
     *
78
     * @var array
79
     */
80
    protected static $cache = array(
81
        'cached'   => array(),
82
        'compiled' => array()
83
    );
84
85
    /**
86
     * Holds the compiler that built this template.
87
     *
88
     * @var ICompiler
89
     */
90
    protected $compiler;
91
92
    /**
93
     * Chmod value for all files written (cached or compiled ones).
94
     * set to null if you don't want any chmod operation to happen
95
     *
96
     * @var int
97
     */
98
    protected $chmod = 0777;
99
100
    /**
101
     * Containing template string.
102
     *
103
     * @var string
104
     */
105
    protected $template;
106
107
    /**
108
     * Creates a template from a string.
109
     *
110
     * @param string $templateString the template to use
111
     * @param int    $cacheTime      duration of the cache validity for this template,
112
     *                               if null it defaults to the Dwoo instance that will
113
     *                               render this template, set to -1 for infinite cache or 0 to disable
114
     * @param string $cacheId        the unique cache identifier of this page or anything else that
115
     *                               makes this template's content unique, if null it defaults
116
     *                               to the current url
117
     * @param string $compileId      the unique compiled identifier, which is used to distinguish this
118
     *                               template from others, if null it defaults to the md4 hash of the template
119
     */
120
    public function __construct($templateString, $cacheTime = null, $cacheId = null, $compileId = null)
121
    {
122
        $this->template  = $templateString;
123
        $this->name      = hash('md4', $templateString);
124
        $this->cacheTime = $cacheTime;
125
126 View Code Duplication
        if ($compileId !== null) {
127
            $this->compileId = str_replace('../', '__', strtr($compileId, '\\%?=!:;' . PATH_SEPARATOR, '/-------'));
128
        } else {
129
            $this->compileId = $templateString;
130
        }
131
132 View Code Duplication
        if ($cacheId !== null) {
133
            $this->cacheId = str_replace('../', '__', strtr($cacheId, '\\%?=!:;' . PATH_SEPARATOR, '/-------'));
134
        }
135
    }
136
137
    /**
138
     * Returns the cache duration for this template.
139
     * defaults to null if it was not provided
140
     *
141
     * @return int|null
142
     */
143
    public function getCacheTime()
144
    {
145
        return $this->cacheTime;
146
    }
147
148
    /**
149
     * Sets the cache duration for this template.
150
     * can be used to set it after the object is created if you did not provide
151
     * it in the constructor
152
     *
153
     * @param int $seconds duration of the cache validity for this template, if
154
     *                     null it defaults to the Dwoo instance's cache time. 0 = disable and
155
     *                     -1 = infinite cache
156
     */
157
    public function setCacheTime($seconds = null)
158
    {
159
        $this->cacheTime = $seconds;
160
    }
161
162
    /**
163
     * Returns the chmod value for all files written (cached or compiled ones).
164
     * defaults to 0777
165
     *
166
     * @return int|null
167
     */
168
    public function getChmod()
169
    {
170
        return $this->chmod;
171
    }
172
173
    /**
174
     * Set the chmod value for all files written (cached or compiled ones).
175
     * set to null if you don't want to do any chmod() operation
176
     *
177
     * @param int $mask new bitmask to use for all files
178
     */
179
    public function setChmod($mask = null)
180
    {
181
        $this->chmod = $mask;
182
    }
183
184
    /**
185
     * Returns the template name.
186
     *
187
     * @return string
188
     */
189
    public function getName()
190
    {
191
        return $this->name;
192
    }
193
194
    /**
195
     * Returns the resource name for this template class.
196
     *
197
     * @return string
198
     */
199
    public function getResourceName()
200
    {
201
        return 'string';
202
    }
203
204
    /**
205
     * Returns the resource identifier for this template, false here as strings don't have identifiers.
206
     *
207
     * @return false
208
     */
209
    public function getResourceIdentifier()
210
    {
211
        return false;
212
    }
213
214
    /**
215
     * Returns the template source of this template.
216
     *
217
     * @return string
218
     */
219
    public function getSource()
220
    {
221
        return $this->template;
222
    }
223
224
    /**
225
     * Returns an unique value identifying the current version of this template,
226
     * in this case it's the md4 hash of the content.
227
     *
228
     * @return string
229
     */
230
    public function getUid()
231
    {
232
        return $this->name;
233
    }
234
235
    /**
236
     * Returns the compiler used by this template, if it was just compiled, or null.
237
     *
238
     * @return ICompiler
239
     */
240
    public function getCompiler()
241
    {
242
        return $this->compiler;
243
    }
244
245
    /**
246
     * Marks this template as compile-forced, which means it will be recompiled even if it
247
     * was already saved and wasn't modified since the last compilation. do not use this in production,
248
     * it's only meant to be used in development (and the development of dwoo particularly).
249
     */
250
    public function forceCompilation()
251
    {
252
        $this->compilationEnforced = true;
253
    }
254
255
    /**
256
     * Returns the cached template output file name, true if it's cache-able but not cached
257
     * or false if it's not cached.
258
     *
259
     * @param Core $core the dwoo instance that requests it
260
     *
261
     * @return string|bool
262
     */
263
    public function getCachedTemplate(Core $core)
264
    {
265
        $cacheLength = $core->getCacheTime();
266
        if ($this->cacheTime !== null) {
267
            $cacheLength = $this->cacheTime;
268
        }
269
270
        // file is not cacheable
271
        if ($cacheLength == 0) {
272
            return false;
273
        }
274
275
        $cachedFile = $this->getCacheFilename($core);
276
277
        if (isset(self::$cache['cached'][$this->cacheId]) === true && file_exists($cachedFile)) {
278
            // already checked, return cache file
279
            return $cachedFile;
280
        } elseif ($this->compilationEnforced !== true && file_exists($cachedFile) && ($cacheLength === - 1 || filemtime($cachedFile) > ($_SERVER['REQUEST_TIME'] - $cacheLength)) && $this->isValidCompiledFile($this->getCompiledFilename($core))) {
281
            // cache is still valid and can be loaded
282
            self::$cache['cached'][$this->cacheId] = true;
283
284
            return $cachedFile;
285
        }
286
287
        // file is cacheable
288
        return true;
289
    }
290
291
    /**
292
     * Caches the provided output into the cache file.
293
     *
294
     * @param Core   $core   the dwoo instance that requests it
295
     * @param string $output the template output
296
     *
297
     * @return mixed full path of the cached file or false upon failure
298
     */
299
    public function cache(Core $core, $output)
300
    {
301
        $cacheDir   = $core->getCacheDir();
302
        $cachedFile = $this->getCacheFilename($core);
303
304
        // the code below is courtesy of Rasmus Schultz,
305
        // thanks for his help on avoiding concurency issues
306
        $temp = tempnam($cacheDir, 'temp');
307
        if (!($file = @fopen($temp, 'wb'))) {
308
            $temp = $cacheDir . uniqid('temp');
309
            if (!($file = @fopen($temp, 'wb'))) {
310
                trigger_error('Error writing temporary file \'' . $temp . '\'', E_USER_WARNING);
311
312
                return false;
313
            }
314
        }
315
316
        fwrite($file, $output);
317
        fclose($file);
318
319
        $this->makeDirectory(dirname($cachedFile), $cacheDir);
320
        if (!@rename($temp, $cachedFile)) {
321
            @unlink($cachedFile);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
322
            @rename($temp, $cachedFile);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
323
        }
324
325
        if ($this->chmod !== null) {
326
            chmod($cachedFile, $this->chmod);
327
        }
328
329
        self::$cache['cached'][$this->cacheId] = true;
330
331
        return $cachedFile;
332
    }
333
334
    /**
335
     * Clears the cached template if it's older than the given time.
336
     *
337
     * @param Core $core      the dwoo instance that was used to cache that template
338
     * @param int  $olderThan minimum time (in seconds) required for the cache to be cleared
339
     *
340
     * @return bool true if the cache was not present or if it was deleted, false if it remains there
341
     */
342
    public function clearCache(Core $core, $olderThan = - 1)
343
    {
344
        $cachedFile = $this->getCacheFilename($core);
345
346
        return !file_exists($cachedFile) || (filectime($cachedFile) < (time() - $olderThan) && unlink($cachedFile));
347
    }
348
349
    /**
350
     * Returns the compiled template file name.
351
     *
352
     * @param Core      $core     the dwoo instance that requests it
353
     * @param ICompiler $compiler the compiler that must be used
354
     *
355
     * @return string
356
     */
357
    public function getCompiledTemplate(Core $core, ICompiler $compiler = null)
358
    {
359
        $compiledFile = $this->getCompiledFilename($core);
360
361
        if ($this->compilationEnforced !== true && isset(self::$cache['compiled'][$this->compileId]) === true) {
362
            // already checked, return compiled file
363
        } elseif ($this->compilationEnforced !== true && $this->isValidCompiledFile($compiledFile)) {
364
            // template is compiled
365
            self::$cache['compiled'][$this->compileId] = true;
366
        } else {
367
            // compiles the template
368
            $this->compilationEnforced = false;
369
370
            if ($compiler === null) {
371
                $compiler = $core->getDefaultCompilerFactory($this->getResourceName());
372
373
                if ($compiler === null || $compiler === array('Dwoo\Compiler', 'compilerFactory')) {
374
                    $compiler = Compiler::compilerFactory();
375
                } else {
376
                    $compiler = call_user_func($compiler);
377
                }
378
            }
379
380
            $this->compiler = $compiler;
381
382
            $compiler->setCustomPlugins($core->getCustomPlugins());
383
            $compiler->setSecurityPolicy($core->getSecurityPolicy());
384
            $this->makeDirectory(dirname($compiledFile), $core->getCompileDir());
385
            file_put_contents($compiledFile, $compiler->compile($core, $this));
386
            if ($this->chmod !== null) {
387
                chmod($compiledFile, $this->chmod);
388
            }
389
390
            if (extension_loaded('Zend OPcache')) {
391
                opcache_invalidate($compiledFile);
392
            } elseif (extension_loaded('apc') && ini_get('apc.enabled')) {
393
                apc_delete_file($compiledFile);
394
            }
395
396
            self::$cache['compiled'][$this->compileId] = true;
397
        }
398
399
        return $compiledFile;
400
    }
401
402
    /**
403
     * Checks if compiled file is valid (it exists).
404
     *
405
     * @param string $file
406
     *
407
     * @return bool True cache file existence
408
     */
409
    protected function isValidCompiledFile($file)
410
    {
411
        return file_exists($file);
412
    }
413
414
    /**
415
     * Returns a new template string object with the resource id being the template source code.
416
     *
417
     * @param Core      $core           the dwoo instance requiring it
418
     * @param mixed     $resourceId     the filename (relative to this template's dir) of the template to include
419
     * @param int       $cacheTime      duration of the cache validity for this template, if null it defaults to the
420
     *                                  Dwoo instance that will render this template if null it defaults to the Dwoo
421
     *                                  instance that will render this template
422
     * @param string    $cacheId        the unique cache identifier of this page or anything else that makes this
423
     *                                  template's content unique, if null it defaults to the current url makes this
424
     *                                  template's content unique, if null it defaults to the current url
425
     * @param string    $compileId      the unique compiled identifier, which is used to distinguish this template from
426
     *                                  others, if null it defaults to the filename+bits of the path template from
427
     *                                  others, if null it defaults to the filename+bits of the path
428
     * @param ITemplate $parentTemplate the template that is requesting a new template object (through an include,
429
     *                                  extends or any other plugin) an include, extends or any other plugin)
430
     *
431
     * @return $this
432
     */
433
    public static function templateFactory(Core $core, $resourceId, $cacheTime = null, $cacheId = null,
434
                                           $compileId = null, ITemplate $parentTemplate = null)
435
    {
436
        return new self($resourceId, $cacheTime, $cacheId, $compileId);
437
    }
438
439
    /**
440
     * Returns the full compiled file name and assigns a default value to it if
441
     * required.
442
     *
443
     * @param Core $core the Core instance that requests the file name
444
     *
445
     * @return string the full path to the compiled file
446
     */
447
    protected function getCompiledFilename(Core $core)
448
    {
449
        return $core->getCompileDir() . hash('md4', $this->compileId) . '.d' . Core::RELEASE_TAG . '.php';
450
    }
451
452
    /**
453
     * Returns the full cached file name and assigns a default value to it if
454
     * required.
455
     *
456
     * @param Core $core the dwoo instance that requests the file name
457
     *
458
     * @return string the full path to the cached file
459
     */
460
    protected function getCacheFilename(Core $core)
461
    {
462
        // no cache id provided, use request_uri as default
463
        if ($this->cacheId === null) {
464
            if (isset($_SERVER['REQUEST_URI']) === true) {
465
                $cacheId = $_SERVER['REQUEST_URI'];
466
            } elseif (isset($_SERVER['SCRIPT_FILENAME']) && isset($_SERVER['argv'])) {
467
                $cacheId = $_SERVER['SCRIPT_FILENAME'] . '-' . implode('-', $_SERVER['argv']);
468
            } else {
469
                $cacheId = '';
470
            }
471
            // force compiled id generation
472
            $this->getCompiledFilename($core);
473
474
            $this->cacheId = str_replace('../', '__',
475
                $this->compileId . strtr($cacheId, '\\%?=!:;' . PATH_SEPARATOR, '/-------'));
476
        }
477
478
        return $core->getCacheDir() . $this->cacheId . '.html';
479
    }
480
481
    /**
482
     * Returns some php code that will check if this template has been modified or not.
483
     * if the function returns null, the template will be instanciated and then the Uid checked
484
     *
485
     * @return string
486
     */
487
    public function getIsModifiedCode()
488
    {
489
        return null;
490
    }
491
492
    /**
493
     * Ensures the given path exists.
494
     *
495
     * @param string $path    any path
496
     * @param string $baseDir the base directory where the directory is created
497
     *                        ($path must still contain the full path, $baseDir
498
     *                        is only used for unix permissions)
499
     *
500
     * @throws Exception
501
     */
502
    protected function makeDirectory($path, $baseDir = null)
503
    {
504
        if (is_dir($path) === true) {
505
            return;
506
        }
507
508
        if ($this->chmod === null) {
509
            $chmod = 0777;
510
        } else {
511
            $chmod = $this->chmod;
512
        }
513
514
        $retries = 3;
515
        while ($retries --) {
516
            @mkdir($path, $chmod, true);
0 ignored issues
show
Security Best Practice introduced by
It seems like you do not handle an error condition here. This can introduce security issues, and is generally not recommended.

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
517
            if (is_dir($path)) {
518
                break;
519
            }
520
            usleep(20);
521
        }
522
523
        // enforce the correct mode for all directories created
524
        if (strpos(PHP_OS, 'WIN') !== 0 && $baseDir !== null) {
525
            $path    = strtr(str_replace($baseDir, '', $path), '\\', '/');
526
            $folders = explode('/', trim($path, '/'));
527
            foreach ($folders as $folder) {
528
                $baseDir .= $folder . DIRECTORY_SEPARATOR;
529
                if (!chmod($baseDir, $chmod)) {
530
                    throw new Exception('Unable to chmod ' . "$baseDir to $chmod: " . print_r(error_get_last(), true));
531
                }
532
            }
533
        }
534
    }
535
}
536