Log::setLogLevel()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
ccs 0
cts 0
cp 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
namespace net\authorize\util;
3
4
use net\authorize\util\ANetSensitiveFields;
5
6 1
define ("ANET_LOG_FILES_APPEND",true);
7 1
8
define("ANET_LOG_DEBUG_PREFIX","DEBUG");
9 1
define("ANET_LOG_INFO_PREFIX","INFO");
10 1
define("ANET_LOG_WARN_PREFIX","WARN");
11 1
define("ANET_LOG_ERROR_PREFIX","ERROR");
12 1
13
//log levels
14
define('ANET_LOG_DEBUG',1);
15 1
define("ANET_LOG_INFO",2);
16 1
define("ANET_LOG_WARN",3);
17 1
define("ANET_LOG_ERROR",4);
18 1
19
//set level
20
define("ANET_LOG_LEVEL",ANET_LOG_DEBUG);
21 1
22
/**
23
 * A class to implement logging.
24
 *
25
 * @package    AuthorizeNet
26
 * @subpackage net\authorize\util
27
 */
28
29
class Log
30
{
31
    private $sensitiveXmlTags = NULL;
32
    private $logFile = '';
33
    private $logLevel = ANET_LOG_LEVEL;
34
	
35
	/**
36
	* Takes a regex pattern (string) as argument and adds the forward slash delimiter.
37
	* Also adds the u flag to enable Unicode mode regex.
38
	*
39
	* @param string $regexPattern
40
	*
41
	* @return string
42 8
	*/
43
	private function addDelimiterFwdSlash($regexPattern)
44 8
	{
45
		return '/'.$regexPattern.'/u';
46
	}
47
	
48
	/**
49
	* Takes an xml as string and masks the sensitive fields.
50
	*
51
	* @param string $rawString		The xml as a string.
52
	*
53
	* @return string 		The xml as a string after masking sensitive fields
54 8
	*/
55 8
    private function maskSensitiveXmlString($rawString){
56 8
        $patterns=array();
57
        $replacements=array();
58 8
		
59 8
        foreach ($this->sensitiveXmlTags as $i => $sensitiveTag){
60 8
            $tag = $sensitiveTag->tagName;
61 8
            $inputPattern = "(.+)"; //no need to mask null data
62
            $inputReplacement = "xxxx";
63 8
64 8
            if(trim($sensitiveTag->pattern)) {
65
                $inputPattern = $sensitiveTag->pattern;
66 8
            }
67 8
            $pattern = "<" . $tag . ">(?:.*)". $inputPattern ."(?:.*)<\/" . $tag . ">";
68
			$pattern = $this->addDelimiterFwdSlash($pattern);
69 8
70 8
            if(trim($sensitiveTag->replacement)) {
71
                $inputReplacement = $sensitiveTag->replacement;
72 8
            }
73
            $replacement = "<" . $tag . ">" . $inputReplacement . "</" . $tag . ">";
74 8
75 8
            $patterns [$i] = $pattern;
76
            $replacements[$i]  = $replacement;
77 8
        }
78 8
        $maskedString = preg_replace($patterns, $replacements, $rawString);
79
        return $maskedString;
80
    }
81
82
    /**
83
     * Takes a string and masks credit card regex matching parts.
84
     *
85
     * @param string $rawString		The string.
86
     *
87
     * @return string 		The string after masking credit card regex matching parts.
88 8
     */
89 8
    private function maskCreditCards($rawString){
90 8
        $patterns=array();
91
        $replacements=array();
92 8
93 8
        foreach ($this->sensitiveStringRegexes as $i => $creditCardRegex){
0 ignored issues
show
Bug introduced by
The property sensitiveStringRegexes does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
94 8
            $pattern = $creditCardRegex;
95
			$pattern = $this->addDelimiterFwdSlash($pattern);
96 8
97 8
            $replacement = "xxxx";
98 8
            $patterns [$i] = $pattern;
99
            $replacements[$i]  = $replacement;
100 8
        }
101 8
        $maskedString = preg_replace($patterns, $replacements, $rawString);
102
        return $maskedString;
103
    }
104
	
105
	/**
106
	* Object data masking related functions START
107
	*/
108
	
109
	/**
110
	* private function getPropertiesInclBase($reflClass).
111
	* 
112
	* Receives a ReflectionObject, ...
113
	* iteratively fetches the properties of the object (including from the base classes up the hierarchy), ...
114
	* collects them in an array of ReflectionProperty and returns the array.
115
	*
116
	* @param ReflectionObject $reflClass
117
	*
118
	* @return \ReflectionProperty[]
119 8
	*/
120
	private function getPropertiesInclBase($reflClass)
121 8
	{
122
		$properties = array();
123
		try {
124 8
			do {
125 8
				$curClassPropList = $reflClass->getProperties();
126 8
				foreach ($curClassPropList as $p) {
127
					$p->setAccessible(true);
128 8
				}
129 8
				$properties = array_merge($curClassPropList, $properties);
130
			} while ($reflClass = $reflClass->getParentClass());
131 8
		} catch (\ReflectionException $e) { }
0 ignored issues
show
Coding Style Comprehensibility introduced by
Consider adding a comment why this CATCH block is empty.
Loading history...
132
		return $properties;
133
	}
134
	
135
	/**
136
	* private function checkPropertyAndMask($prop, $obj).
137
	* 
138
	* Receives a ReflectionProperty and an object, and returns a masked object if the ReflectionProperty corresponds to a sensitive field, else returns false.
139
	*
140
	* @param ReflectionProperty $prop
141
	* @param object $obj
142
	*
143
	* @return string|bool
144 8
	*/
145 8
	private function checkPropertyAndMask($prop, $obj){
146
		foreach($this->sensitiveXmlTags as $i => $sensitiveField)
147 8
		{
148 8
			$inputPattern = "(.+)";
149
			$inputReplacement = "xxxx";
150 8
151 8
            if(trim($sensitiveField->pattern)) {
152
                $inputPattern = $sensitiveField->pattern;
153 8
            }
154
			$inputPattern = $this->addDelimiterFwdSlash($inputPattern);
155 8
			
156 8
            if(trim($sensitiveField->replacement)) {
157
                $inputReplacement = $sensitiveField->replacement;
158
            }
159 8
			
160
			if(strcmp($prop->getName(),$sensitiveField->tagName)==0)
161 8
			{
162 8
				$prop->setValue($obj,preg_replace($inputPattern,$inputReplacement,$prop->getValue($obj)));
163
				return $prop->getValue($obj);
164
			}
165 8
		}
166
		return false;
167
	}
168
	
169
	/**
170
	* called by getMasked() to mask sensitive fields of an object.
171
	*
172
	* @param object $obj
173
	*
174
	* @return object
175 8
	*/
176
    private function maskSensitiveProperties ($obj)
177
    {
178 8
		// first retrieve all properties of the passed object
179 8
        $reflectObj = new \ReflectionObject($obj);
180
        $props = $this->getPropertiesInclBase($reflectObj);
0 ignored issues
show
Documentation introduced by
$reflectObj is of type object<ReflectionObject>, but the function expects a object<net\authorize\util\ReflectionObject>.

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...
181
182 8
		// for composite property recursively execute; for scalars, do a check and mask
183 8
        foreach($props as $i => $prop){
184
			$propValue=$prop->getValue($obj);
185
			
186 8
			// for object and arrays, recursively call for inner elements
187 8
			if(is_object($propValue)){
188
				$prop->setValue($obj, $this->maskSensitiveProperties($propValue));
189 8
            }
190
			else if(is_array($propValue)){
191
				$newVals=array();
192
				foreach($propValue as $i=>$arrEle)
193
				{
194
					$newVals[]=$this->maskSensitiveProperties($arrEle);
195
				}
196
				$prop->setValue($obj, $newVals);
197
            }
198
			// else check if the property represents a sensitive field. If so, mask.
199 8
            else{
200 8
				$res=$this->checkPropertyAndMask($prop, $obj);
0 ignored issues
show
Documentation introduced by
$prop is of type object<ReflectionProperty>, but the function expects a object<net\authorize\util\ReflectionProperty>.

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...
201 8
				if($res)
202
					$prop->setValue($obj, $res);
203
            }
204
        }
205 8
		
206
        return $obj;
207
    }
208
	
209
	/**
210
	* Object data masking related functions END
211
	*/
212
	
213
	/**
214
	* private function getMasked($raw).
215
	*
216
	* called by log()
217
	*
218
	* @param mixed $raw
219
	*
220
	* @return string
221 8
	*/
222
    private function getMasked($raw)
223 8
    { //always returns string
224 8
        $messageType = gettype($raw);
225 8
        $message="";
0 ignored issues
show
Unused Code introduced by
$message is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
226 8
        if($messageType == "object"){
227 8
			$obj = unserialize(serialize($raw)); // deep copying the object
228
			$message = print_r($this->maskSensitiveProperties($obj), true); //object to string
229 8
        }
230
        else if($messageType == "array"){
231
            $copyArray = unserialize(serialize($raw));
232
            foreach($copyArray as $i => $element){
233
                $copyArray[$i] = $this->getMasked($element);
234
            }
235
            $message = print_r($copyArray, true); // returns string
236
        }
237 8
        else { //$messageType == "string")
238
            $primtiveTypeAsString = strval($raw);
239 8
240 8
            $maskedXml = $primtiveTypeAsString;
241 8
            if($messageType == "string") {
242
                $maskedXml = $this->maskSensitiveXmlString($primtiveTypeAsString);
243
            }
244 8
            //mask credit card numbers
245
            $message = $this->maskCreditCards($maskedXml);
246 8
        }
247
        return $message;
248
    }
249 8
	
250
	private function log($logLevelPrefix, $logMessage, $flags){
251 8
        if (!$this->logFile) return;
252
        //masking
253
        $logMessage = $this->getMasked($logMessage);
254 8
255 8
        //debug_backtrace
256 8
        $fileName = 'n/a';
257 8
        $methodName = 'n/a';
258 8
        $lineNumber = 'n/a';
259 8
        $debugTrace = debug_backtrace();
260 8
        if (isset($debugTrace[1])) {
261
            $fileName = $debugTrace[1]['file'] ? $debugTrace[1]['file'] : 'n/a';
262 8
            $lineNumber = $debugTrace[1]['line'] ? $debugTrace[1]['line'] : 'n/a';
263
        }
264
        if (isset($debugTrace[2])) $methodName = $debugTrace[2]['function'] ? $debugTrace[2]['function'] : 'n/a';
265 8
266
        //Add timestamp, log level, method, file, line
267 8
        $logString = sprintf("\n %s %s : [%s] (%s : %s) - %s", \net\authorize\util\Helpers::now(), $logLevelPrefix,
268 8
            $methodName, $fileName, $lineNumber, $logMessage);
269
        file_put_contents($this->logFile, $logString, $flags);
270 8
    }
271
	
272 8
    public function debug($logMessage, $flags=FILE_APPEND)
273 8
    {
274
        if(ANET_LOG_DEBUG >= $this->logLevel){
275 8
            $this->log(ANET_LOG_DEBUG_PREFIX, $logMessage,$flags);
276
        }
277 8
    }
278 8
	
279 8
    public function info($logMessage, $flags=FILE_APPEND){
280
        if(ANET_LOG_INFO >= $this->logLevel) {
281 8
            $this->log(ANET_LOG_INFO_PREFIX, $logMessage,$flags);
282
        }
283
    }
284
	
285
	public function warn($logMessage, $flags=FILE_APPEND){
286
        if(ANET_LOG_WARN >= $this->logLevel) {
287
            $this->log(ANET_LOG_WARN_PREFIX, $logMessage,$flags);
288
        }
289
    }
290
	
291
    public function error($logMessage, $flags=FILE_APPEND){
292
        if(ANET_LOG_ERROR >= $this->logLevel) {
293
            $this->log(ANET_LOG_ERROR_PREFIX, $logMessage,$flags);
294
        }
295
    }
296
	
297
	private function logFormat($logLevelPrefix, $format, $objects, $flags){
298
        try {
299
            foreach($objects as $i => $testObject){
300
                $objects[$i] = $this->getMasked($testObject);
301
            }
302
            $logMessage = vsprintf($format, $objects);
303
            $this->log($logLevelPrefix, $logMessage, $flags);
304
        }
305
        catch(\Exception $e){
306
            $this->debug("Incorrect log message format: " . $e->getMessage());
307
        }
308
    }
309
	
310
	public function debugFormat($format, $args=array(),  $flags=FILE_APPEND)
311
    {
312
        if(ANET_LOG_DEBUG >= $this->logLevel){
313
            $this->logFormat(ANET_LOG_DEBUG_PREFIX, $format, $args , $flags);
314
        }
315
    }
316
	
317
	public function infoFormat($format, $args=array(),  $flags=FILE_APPEND){
318
        if(ANET_LOG_INFO >= $this->logLevel) {
319
            $this->logFormat(ANET_LOG_INFO_PREFIX, $format, $args , $flags);
320
        }
321
    }
322
	
323
	public function warnFormat($format, $args=array(),  $flags=FILE_APPEND){
324
        if(ANET_LOG_WARN >= $this->logLevel) {
325
            $this->logFormat(ANET_LOG_WARN_PREFIX, $format, $args , $flags);
326
        }
327
    }
328
	
329
    public function errorFormat($format, $args=array(),  $flags=FILE_APPEND){
330
        if(ANET_LOG_ERROR >= $this->logLevel) {
331
			$this->logFormat(ANET_LOG_ERROR_PREFIX, $format, $args , $flags);
332
        }
333 1
    }
334 1
335 1
    /**
336 1
     * @param string $logLevel
337
     * possible values = ANET_LOG_DEBUG, ANET_LOG_INFO, ANET_LOG_WARN, ANET_LOG_ERROR
338
     */
339
    public function setLogLevel($logLevel){
340
        $this->logLevel = $logLevel;
341
    }
342
343
    /**
344
     * @return string
345
     */
346
    public function getLogLevel(){
347
        return $this->logLevel;
348
    }
349
350
    /**
351
     * @param string $logFile
352
     */
353
    public function setLogFile($logFile){
354
        $this->logFile = $logFile;
355
    }
356
357
    /**
358
     * @return string
359
     */
360
    public function getLogFile(){
361
        return $this->logFile;
362
    }
363
	
364
    public function __construct(){
365
        $this->sensitiveXmlTags = ANetSensitiveFields::getSensitiveXmlTags();
366
        $this->sensitiveStringRegexes = ANetSensitiveFields::getSensitiveStringRegexes();
367
    }
368
}
369
?>
0 ignored issues
show
Best Practice introduced by
It is not recommended to use PHP's closing tag ?> in files other than templates.

Using a closing tag in PHP files that only contain PHP code is not recommended as you might accidentally add whitespace after the closing tag which would then be output by PHP. This can cause severe problems, for example headers cannot be sent anymore.

A simple precaution is to leave off the closing tag as it is not required, and it also has no negative effects whatsoever.

Loading history...
370