Issues (1751)

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/ar/cache.php (7 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
	/* usage
4
5
		simple:
6
7
		if ( !$image = ar('cache')->getIfFresh( $name ) ) {
8
			$image = expensiveOperation();
9
			ar('cache')->set( $naam, $image );
10
		}
11
		echo $image;
12
13
		with locking:
14
15
		if ( !$image = ar('cache')->getIfFresh( $naam ) ) {
16
			if ( ar('cache')->lock( $naam ) ) {
17
				$image = expensiveOperation();
18
				ar('cache')->set( $naam, $image, '2 hours' );
19
			} else if ( ar('cache')->wait( $naam ) ) { // lock failed, another process is generating the cache
20
				// continues here when the lock to be lifted
21
				$image = ar('cache')->get($naam);
22
			} else {
23
				// couldn't lock the file in a reasonable time, you could generate an error here
24
				// or just go with a stale image, or simply do the calculation:
25
				$image = expensiveOperation();
26
			}
27
		}
28
		echo $image;
29
30
	*/
31
32
	ar_pinp::allow('ar_cache');
33
	ar_pinp::allow('ar_cacheStore');
34
	ar_pinp::allow('ar_cacheProxy');
35
36
	class ar_cache extends arBase {
37
38
		public static $cacheStore = null;
39
40
		public static function config( $options ) {
41
			if ( $options['cacheStore'] ) {
42
				self::$cacheStore = $options['cacheStore'];
43
			}
44
		}
45
46
		public static function create( $prefix = null, $timeout = 7200 ) {
47
			// this method is used by pinp scripts to create a specific cache
48
			// so it must be more restrictive than the constructor of the cacheStore
49
			// which must be able to clear any and all caches
50
			if ( !$prefix ) { // make sure you have a default prefix, so you won't clear other prefixes unintended
51
				$prefix = 'default';
52
			}
53
			$prefix = 'pinp/'.$prefix; // make sure the pinp scripts have their own top level
54
			$prefix = $prefix . ar::context()->getPath(); // make sure the cache store is limited to the current path in the context stack
55
			try {
56
				return new ar_cacheStore( $prefix, $timeout );
57
			} catch( Exception $e ) {
58
				return ar_error::raiseError( $e->getMessage(), $e->getCode() );
59
			}
60
		}
61
62
		public static function get( $name ) {
63
			if ( !self::$cacheStore ) {
64
				self::$cacheStore = self::create();
65
			}
66
			return self::$cacheStore->get( $name );
67
		}
68
69
		public static function getIfFresh( $name, $freshness=0 ) {
70
			if ( !self::$cacheStore ) {
71
				self::$cacheStore = self::create();
72
			}
73
			return self::$cacheStore->getIfFresh( $name, $freshness );
0 ignored issues
show
The method getIfFresh does only exist in ar_cacheStore, but not in ar_error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
74
		}
75
76
		public static function lock( $name ) {
77
			if ( !self::$cacheStore ) {
78
				self::$cacheStore = self::create();
79
			}
80
			return self::$cacheStore->lock( $name );
0 ignored issues
show
The method lock does only exist in ar_cacheStore, but not in ar_error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
81
		}
82
83
		public static function wait( $name ) {
84
			if ( !self::$cacheStore ) {
85
				self::$cacheStore = self::create();
86
			}
87
			return self::$cacheStore->wait( $name );
0 ignored issues
show
The method wait does only exist in ar_cacheStore, but not in ar_error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
88
		}
89
90
		public static function set( $name, $value, $timeout = 7200 ) {
91
			if ( !self::$cacheStore ) {
92
				self::$cacheStore = self::create();
93
			}
94
			return self::$cacheStore->set( $name, $value, $timeout );
0 ignored issues
show
The method set does only exist in ar_cacheStore, but not in ar_error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
95
		}
96
97
		public static function info( $name ) {
98
			if ( !self::$cacheStore ) {
99
				self::$cacheStore = self::create();
100
			}
101
			return self::$cacheStore->info( $name );
0 ignored issues
show
The method info does only exist in ar_cacheStore, but not in ar_error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
102
		}
103
104
		public static function clear( $name = null ) {
105
			if ( !self::$cacheStore ) {
106
				self::$cacheStore = self::create();
107
			}
108
			return self::$cacheStore->clear( $name );
0 ignored issues
show
The method clear does only exist in ar_cacheStore, but not in ar_error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
109
		}
110
111
		public static function purge( $name = null ) {
112
			if ( !self::$cacheStore ) {
113
				self::$cacheStore = self::create();
114
			}
115
			return self::$cacheStore->purge( $name );
0 ignored issues
show
The method purge does only exist in ar_cacheStore, but not in ar_error.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
116
		}
117
118
		public static function proxy( $object, $timeout = null ) {
119
			if ( !self::$cacheStore ) {
120
				self::$cacheStore = self::create();
121
			}
122
			return new ar_cacheProxy( $object, self::$cacheStore, $timeout );
123
		}
124
125
	}
126
127
	class ar_cacheProxy extends arWrapper {
128
		// TODO: allow more control on retrieval:
129
		// - get contents from cache even though cache may be stale
130
		//   perhaps through an extra option in __construct?
131
		public $cacheStore = null;
132
		public $cacheController = null;
133
		public $cacheTimeout = '2 hours';
134
135
		public function __construct( $object, $cacheStore, $cacheTimeout = null, $cacheController = null ) {
136
			parent::__construct( $object );
137
			$this->cacheStore = $cacheStore;
138
			$this->cacheController = $cacheController;
139
			if ( isset($cacheTimeout) ) {
140
				$this->cacheTimeout = $cacheTimeout;
141
			}
142
		}
143
144
		protected function __callCatch( $method, $args ) {
145
			ob_start();
146
			$result = parent::__call( $method, $args );
147
			$output = ob_get_contents();
148
			ob_end_clean();
149
			return array(
150
				'output' => $output,
151
				'result' => $result
152
			);
153
		}
154
155
		protected function __callCached( $method, $args, $path ) {
156
			if ( !$cacheData = $this->cacheStore->getIfFresh( $path ) ) {
157
				if ( $this->cacheStore->lock( $path ) ) {
158
					$cacheData = $this->__callCatch( $method, $args );
159
					$this->cacheStore->set( $path, $cacheData, $this->cacheTimeout );
160
				} else if ( $this->cacheStore->wait( $path ) ){
161
					$cacheData = $this->cacheStore->get( $path );
162
				} else {
163
					$cacheData = $this->__callCatch( $method, $args ); // just get the result and return it
164
				}
165
			}
166
			return $cacheData;
167
		}
168
169
		public function __call( $method, $args ) {
170
			$path = $method . '(' . md5( serialize($args) ) . ')';
171
			$cacheData = $this->__callCached( $method, $args, $path );
172
			echo $cacheData['output'];
173
			$result = $cacheData['result'];
174
			if ( is_object( $result ) ) {
175
				$result = new ar_cacheProxy( $result, $this->cacheStore->subStore( $path ) );
176
			}
177
			return $result;
178
		}
179
180
		public function __get( $name ) {
181
			$result = parent::__get( $name );
182
			if ( is_object( $result ) ) {
183
				$result = new ar_cacheProxy( $result, $this->cacheStore->subStore( $name ) );
184
			}
185
			return $result;
186
		}
187
188
	}
189
190
	interface ar_cacheStoreInterface {
191
		public function get( $path );
192
		public function set( $path, $value, $timeout = 7200 );
193
		public function info( $path );
194
		public function clear( $path = null );
195
		public function subStore( $path );
196
		public function isFresh( $path );
197
		public function purge( $name = null );
198
		public function getIfFresh( $name, $freshness=0 );
199
	}
200
201
	class ar_cacheStore implements ar_cacheStoreInterface, arKeyValueStoreInterface {
202
203
		protected $basePath = '';
204
		protected $timeout = 7200;
205
		protected $mode = 0777;
206
207
		public function __construct( $basePath, $timeout = 7200, $mode = 0777 ) {
208
			$this->basePath = preg_replace('/\.\./', '', $basePath);
209
210
			if ( is_string($timeout) ) {
211
				$timeout = strtotime( $timeout, 0);
212
			}
213
			$this->timeout = $timeout;
214
			$this->mode = $mode;
215
216
			if ( !defined("ARCacheDir") ) {
217
				define( "ARCacheDir", sys_get_temp_dir().'/ar_cache/' );
218
			}
219
			if ( !file_exists( ARCacheDir ) ) {
220
				mkdir( ARCacheDir, $this->mode );
221
			}
222
			if ( !file_exists( ARCacheDir ) ) {
223
				throw new ar_error("Cache Directory does not exist ( ".ARCacheDir." )", 1);
224
			}
225
			if ( !is_dir( ARCacheDir ) ) {
226
				throw new ar_error("Cache Directory is not a directory ( ".ARCacheDir." )", 1);
227
			}
228
			if ( !is_writable( ARCacheDir ) ) {
229
				throw new ar_error("Cache Directory is not writable ( ".ARCacheDir." )", 1);
230
			}
231
		}
232
233
		protected function cachePath( $path ) {
234
			// last '=' is added to prevent conflicts between subdirectories and cache images
235
			// images always end in a '=', directories never end in a '='
236
			return ARCacheDir . $this->basePath . preg_replace('/(\.\.|\=)/', '', $path) . '=';
237
		}
238
239
		public function subStore( $path ) {
240
			return new ar_cacheStore( $this->basePath . preg_replace('/(\.\.|\=)/', '', $path) );
241
		}
242
243
		public function get( $path ) {
244
			$cachePath = $this->cachePath( $path );
245
			if ( file_exists( $cachePath ) ) {
246
				return unserialize( file_get_contents( $cachePath ) );
247
			} else {
248
				return null;
249
			}
250
		}
251
252
		public function getvar( $name ) {
253
			return $this->get( $name );
254
		}
255
256
		public function isFresh( $path ) {
257
			$cachePath = $this->cachePath( $path );
258
			if ( file_exists( $cachePath ) ) {
259
				return ( filemtime( $cachePath ) > time() );
260
			} else {
261
				return false;
262
			}
263
		}
264
265
		public function getIfFresh( $path, $freshness = 0 ) {
266
			$info = $this->info( $path );
267
			if ( $info && $info['timeout'] >= $freshness ) {
268
				return $this->get( $path );
269
			} else {
270
				return false;
271
			}
272
		}
273
274
		public function lock( $path, $blocking = false ) {
275
			// locks the file against writing by other processes, so generation of time or resource expensive images
276
			// will not happen by multiple processes simultaneously
277
			$cachePath = $this->cachePath( $path );
278
			$dir = dirname( $cachePath );
279
			if ( !file_exists( $dir ) ) {
280
				mkdir( $dir, $this->mode, true ); //recursive
281
			}
282
			$lockFile = fopen( $cachePath, 'c' );
283
			$lockMode = LOCK_EX;
284
			if ( !$blocking ) {
285
				$lockMode = $lockMode|LOCK_NB;
286
			}
287
			return flock( $lockFile, $lockMode );
288
		}
289
290
		public function wait( $path ) {
291
			$cachePath = $this->cachePath( $path );
292
			$lockFile = fopen( $cachePath, 'c' );
293
			$result = flock( $lockFile, LOCK_EX );
294
			fclose( $lockFile );
295
			return $result;
296
		}
297
298
		public function putvar( $name, $value ) {
299
			return $this->set( $name, $value );
300
		}
301
302
		public function set( $path, $value, $timeout = null ) {
303
			$cachePath = $this->cachePath( $path );
304
			if ( !isset( $timeout ) ) {
305
				$timeout = $this->timeout;
306
			}
307
			if ( is_string( $timeout ) ) {
308
				$timeout = strtotime( $timeout, 0);
309
			}
310
			$dir = dirname( $cachePath );
311
			if ( !file_exists( $dir ) ) {
312
				mkdir( $dir, $this->mode, true ); //recursive
313
			}
314
			if ( false !== file_put_contents( $cachePath, serialize( $value ), LOCK_EX ) ) {
315
				// FIXME: check dat de lock gemaakt met lock() weg is na file_put_contents
316
				touch( $cachePath, time() + $timeout );
317
			} else {
318
				return false;
319
			}
320
		}
321
322
		public function info( $path ) {
323
			$cachePath = $this->cachePath( $path );
324
			if ( file_exists( $cachePath ) && is_readable( $cachePath ) ) {
325
				return array(
326
					'size' => filesize($cachePath),
327
					'fresh' => $this->isFresh( $path ),
328
					'ctime' => filectime( $cachePath ),
329
					'timeout' => filemtime( $cachePath ) - time()
330
				);
331
			} else {
332
				return false;
333
			}
334
		}
335
336
		public function clear( $path = null ) {
337
			$cachePath = $this->cachePath( $path );
338
			if ( file_exists( $cachePath ) ) {
339
				return unlink( $cachePath );
340
			} else {
341
				return true;
342
			}
343
		}
344
345
		public function purge( $path = null ) {
346
			$this->clear( $path );
347
			$cachePath = substr( $this->cachePath( $path ), 0, -1 ); // remove last '='
348
			if ( file_exists( $cachePath ) ) {
349
				if ( is_dir( $cachePath ) ){
350
					$cacheDir = dir( $cachePath );
351
					while (false !== ($entry = $cacheDir->read())) {
352
						if ( $entry != '.' && $entry != '..' ) {
353
							$this->purge( $path . '/' . $entry );
354
						}
355
					}
356
					return rmdir( $cachePath );
357
				} else {
358
					return unlink( $cachePath );
359
				}
360
			} else {
361
				return true;
362
			}
363
		}
364
	}
365