Issues (16)

Security Analysis    no request data  

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

  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.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  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.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  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.
  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.
  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.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  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.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  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.
  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.
  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.
  Header Injection
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/SmtpChecker.php (5 issues)

1
<?php
2
3
/*
4
 * This file is part of EmailChecker.
5
 *
6
 * (c) Corrado Ronci <[email protected]>
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
12
namespace sorciulus\EmailChecker;
13
14
use sorciulus\EmailChecker\Exception\SmtpCheckerException;
15
use sorciulus\EmailChecker\MxChecker;
16
use \Graze\TelnetClient\Exception\TelnetException;
0 ignored issues
show
The type Graze\TelnetClient\Exception\TelnetException was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
17
use \miyahan\network\Telnet;
18
/**
19
* This Class check the email address is valid 
20
* through commands executed on the SMTP Server
21
*/
22
class SmtpChecker implements SmtpInterface
23
{
24
	/**
25
	 * Instance of Telnet class
26
	 * @var object Telnet
27
	 */
28
	private $client;
29
30
	/**
31
	 * The domain of SMTP Server
32
	 * @var string
33
	 */
34
	private $domain;
35
36
	/**
37
	 * Response Code SMTP Server
38
	 * @var integer
39
	 */
40
	private $code;
41
42
	/**
43
	 * The given email is valid or not.
44
	 * @var boolean
45
	 */
46
	private $isValid;
47
48
	/**
49
	 * List of command and response executed
50
	 * @var array
51
	 */
52
	private $debug = [];
53
54
	/**
55
	 * The sender of SMTP check email
56
	 * @var string
57
	 */
58
	private $sender = "[email protected]";
59
60
	// some smtp response codes
61
    const SMTP_CONNECT_SUCCESS = 220;
62
    const SMTP_QUIT_SUCCESS = 221;
63
    const SMTP_GENERIC_SUCCESS = 250;
64
    const SMTP_USER_NOT_LOCAL = 251;
65
    const SMTP_CANNOT_VRFY = 252;
66
    const SMTP_SERVICE_UNAVAILABLE = 421;
67
    // 450  Requested mail action not taken: mailbox unavailable (e.g.,
68
    // mailbox busy or temporarily blocked for policy reasons)
69
    const SMTP_MAIL_ACTION_NOT_TAKEN = 450;
70
    // 451  Requested action aborted: local error in processing
71
    const SMTP_MAIL_ACTION_ABORTED = 451;
72
    // 452  Requested action not taken: insufficient system storage
73
    const SMTP_REQUESTED_ACTION_NOT_TAKEN = 452;
74
    // 500  Syntax error (may be due to a denied command)
75
    const SMTP_SYNTAX_ERROR = 500;
76
    // 502  Comment not implemented
77
    const SMTP_NOT_IMPLEMENTED = 502;
78
    // 503  Bad sequence of commands (may be due to a denied command)
79
    const SMTP_BAD_SEQUENCE = 503;
80
    // 550  Requested action not taken: mailbox unavailable (e.g., mailbox
81
    // not found, no access, or command rejected for policy reasons)
82
    const SMTP_MBOX_UNAVAILABLE = 550;
83
    const SMTP_USER_NOT_LOCAL_FORWARD = 551;
84
    // 552  Requested mail action aborted: exceeded storage allocation
85
    const SMTP_EXCEEDED_STORAGE_ALLOCAION = 552;
86
    //553  Requested action not taken: mailbox name not allowed (e.g.,
87
    //mailbox syntax incorrect)
88
    const SMTP_MBOX_NAME_NOT_ALLOWED = 553;
89
    // 554  Seen this from hotmail MTAs, in response to RSET :(
90
    const SMTP_TRANSACTION_FAILED = 554;
91
92
    /**    
93
     * @param array $domains List of SMTP domains 
94
     * @param boolean $sender Set sender of STMP command 
95
     * @param integer $timeout Timeout of the stream
96
     *
97
     * @throws SmtpCheckerException when all domain not valid
98
     */
99
	function __construct(MxInterface $domains, $sender = "", int $timeout = 10)
100
	{						
101
		foreach ($domains->getRecordMx() as $domain) {
102
			try {				
103
				$this->debug  = ["Connect to : ".$domain["target"]." on port 25"];
104
				$this->client = new Telnet($domain["target"], 25, $timeout);								
105
				$this->domain = $domain;
106
				break;
107
			} catch (\Exception $ex) {							
108
				continue;
109
			}
110
		}
111
		if (empty($this->getDomain())) {
112
			throw new SmtpCheckerException("Error Processing Request ".$ex->getMessage());			
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ex seems to be defined by a foreach iteration on line 101. Are you sure the iterator is never empty, otherwise this variable is not defined?
Loading history...
113
		}		
114
				
115
		if (!empty($sender)) {
116
			$this->setSender($sender);
117
		}
118
		$this->sayHello();
119
		$this->setFrom();		
120
	}
121
122
	/**
123
    * Sets the The sender of SMTP check email.
124
    *
125
    * @param string $sender the sender
126
    *
127
    * @return void
128
    */
129
    private function setSender($sender)
130
    {
131
        if (!filter_var($sender, FILTER_VALIDATE_EMAIL)) {
132
			throw new SmtpCheckerException("Email Sender not valid");		
133
		}
134
		$this->sender = $sender;				
135
		       		
136
    }
137
138
	/**
139
    * Gets the value of sender.
140
    *
141
    * @return string
142
    */
143
	private function getSender()
144
	{
145
		return $this->sender;
146
	}
147
148
	/**
149
    * Gets the value of domain.
150
    *
151
    * @return array
152
    */
153
	private function getDomain()
154
	{
155
		return $this->domain;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $this->domain returns the type string which is incompatible with the documented return type array.
Loading history...
156
	}
157
158
	/**
159
    * Gets the value of getDomain in object.
160
    *
161
    * @return object
162
    */
163
	private function getDomainObj()
164
	{
165
		return (object) $this->getDomain();
166
	}
167
168
	/**
169
	 * Send command HELO to SMTP Server
170
	 * 
171
	 * @return void
172
	 *
173
	 * @throws SmtpCheckerException when the SMTP server return error
174
	 */
175 View Code Duplication
	private function sayHello()
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
176
	{
177
		$host = $this->getDomainObj()->host;
178
		try{				
179
			$status = $this->commandExec(sprintf("HELO %s", $host));				
180
			if (!in_array(self::SMTP_GENERIC_SUCCESS, $status)) {
181
				$this->disconnect();
182
				throw new SmtpCheckerException("SMTP Status unexpected: ".implode(",", $status), $this->getDebug());	 
183
			}
184
		}catch (\Exception $ex) {			
185
			throw new SmtpCheckerException("Error Processing Request ".$ex->getMessage(), $this->getDebug());							
186
		}
187
		
188
	}
189
190
	/**
191
	 * Set MAIL FROM to SMTP Server
192
	 * 
193
	 * @return void
194
	 *
195
	 * @throws SmtpCheckerException when the SMTP server return error
196
	 */
197 View Code Duplication
	private function setFrom()
0 ignored issues
show
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
198
	{		
199
		try{
200
			$status = $this->commandExec(sprintf("MAIL FROM:<%s>", $this->getSender()));				
201
			if (!in_array(self::SMTP_GENERIC_SUCCESS, $status)) {
202
				$this->disconnect();
203
				throw new SmtpCheckerException("SMTP Status unexpected: ".implode(",", $status), $this->getDebug());	 
204
			}
205
		}catch (\Exception $ex) {					
206
			throw new SmtpCheckerException("Error Processing Request setFrom : ".$ex->getMessage(), $this->getDebug());
207
		}
208
		
209
	}
210
211
	/**
212
	 * Wrapper to Telnet Client to Execute SMTP command, will return the status code
213
	 * 
214
	 * @param  string $command   command execute
215
	 * @return array  SMPT status
216
	 */
217
	private function commandExec($command)
218
	{		
219
		$this->debug[] = $command;	
220
		$exec = $this->client->exec($command);	
221
		return $this->getResponseStatus($exec);		
222
	}
223
224
	/**
225
	 * Get response status code of previous SMTP request 
226
	 * 
227
	 * @return array $status The status of SMTP request
228
	 *
229
	 * @throws SmtpCheckerException when the SMTP server return unknown error
230
	 */
231
	private function getResponseStatus($output)
232
	{
233
		$status = [];
234
		$strout = explode("\n", $output);			
235
		if (empty($strout)) {
236
			$strout = [$output];
237
		}				
238
		foreach ($strout as $str) {
239
			$this->debug[] = $str;
240
			if(preg_match('/^[0-9]{3}/', $str, $match)) {				
241
				$status[] = current($match);
242
			}
243
		}
244
		if(empty($status)) {			
245
			throw new SmtpCheckerException("SMTP Status request Unknown, ". $output, $this->getDebug());			
246
		}
247
		return $status;
248
	}
249
250
251
	/**
252
	 * Close connection to SMTP Server
253
	 * 
254
	 * @return void
255
	 */
256
	private function disconnect()
257
	{
258
		$this->client->exec("quit");		
259
		$this->client->disconnect();
260
		$this->debug[] = "QUIT";
261
	}
262
263
	/**
264
	 *	Set RCPT command to SMTP server
265
	 * 
266
	 * @param string $email The email to validate
267
	 * @return self
268
	 *
269
	 * @throws SmtpCheckerException when the SMTP server return error
270
	 */
271
	public function validate($email)
272
	{
273
		try{			
274
			$command = sprintf("RCPT TO:<%s>", $email);
275
			$exec = $this->client->exec($command);
276
			$this->debug[] = $command;			
277
			$status = $this->getResponseStatus($exec);										
278
			$this->disconnect();
279
			$this->code = end($status);
280
			$this->isValid = false;
281
			if (in_array($this->getCode(), [self::SMTP_USER_NOT_LOCAL, self::SMTP_GENERIC_SUCCESS])) {
282
				$this->isValid = true;
283
			} 
284
			return $this;			
285
		}catch (\Exception $ex) {						
286
			throw new SmtpCheckerException("Error Processing Request Validate : ".$ex->getMessage(), $this->getDebug());
287
		}
288
	}
289
290
    /**
291
    * Gets the value of code.
292
    *
293
    * @return integer
294
    */
295
    public function getCode()
296
    {
297
        return (int) $this->code;
298
    } 
299
300
    /**
301
    * Gets the value of isValid.
302
    *
303
    * @return boolean
304
    */
305
    public function isValid()
306
    {
307
        return $this->isValid;
308
    }
309
310
    /**
311
    * Gets the value of debug.
312
    *
313
    * @return array
314
    */
315
    public function getDebug()
316
    {
317
        return $this->debug;
318
    } 
319
320
    /**
321
    * Gets the value of message.
322
    *
323
    * @return string
324
    */
325
    public function getMessage()
326
    {
327
        $code     = $this->getCode();
328
        $messages = [
329
        	self::SMTP_CONNECT_SUCCESS => "SMTP connect Success",
330
		    self::SMTP_QUIT_SUCCESS => "Quit Success",
331
		    self::SMTP_GENERIC_SUCCESS => "SMTP Generic Success",
332
		    self::SMTP_USER_NOT_LOCAL => "SMTP User not local",
333
		    self::SMTP_CANNOT_VRFY => "SMTP Cannot VRFY user",
334
		    self::SMTP_SERVICE_UNAVAILABLE => "SMTP Service not available",
335
		    self::SMTP_MAIL_ACTION_NOT_TAKEN => "SMTP mailbox busy or temporarily blocked for policy reasons",		    
336
		    self::SMTP_MAIL_ACTION_ABORTED => "SMTP Requested action aborted: local error in processing",		    
337
		    self::SMTP_REQUESTED_ACTION_NOT_TAKEN => "SMTP Requested action not taken: insufficient system storage",		    
338
		    self::SMTP_SYNTAX_ERROR => "SMTP Syntax error, command unrecognized",		    
339
		    self::SMTP_NOT_IMPLEMENTED => "SMTP Command not implemented",	    
340
		    self::SMTP_BAD_SEQUENCE => "SMTP Bad sequence of commands",
341
		    self::SMTP_MBOX_UNAVAILABLE => "SMTP Requested action not taken: mailbox unavailable",
342
		    self::SMTP_USER_NOT_LOCAL_FORWARD => "SMTP User not local",		    
343
		    self::SMTP_EXCEEDED_STORAGE_ALLOCAION => "SMTP Requested mail action aborted: exceeded storage allocation",		    
344
		    self::SMTP_MBOX_NAME_NOT_ALLOWED => "Requested action not taken: mailbox name not allowed",
345
		    self::SMTP_TRANSACTION_FAILED => "SMTP Transaction failed"
346
        ];
347
348
        return
349
        	(array_key_exists($code, $messages))
350
        	? $messages[$code]
351
        	: "Unknown message from SMTP";
352
    }
353
}