Asymptix /
Framework
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
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 Asymptix\mail; |
||
| 4 | |||
| 5 | /** |
||
| 6 | * Class for working with POP (Post Office Protocol). |
||
| 7 | * |
||
| 8 | * @category Asymptix PHP Framework |
||
| 9 | * @author Dmytro Zarezenko <[email protected]> |
||
| 10 | * @copyright (c) 2010 - 2016, Dmytro Zarezenko |
||
| 11 | * |
||
| 12 | * @git https://github.com/Asymptix/Framework |
||
| 13 | * @license http://opensource.org/licenses/MIT |
||
| 14 | */ |
||
| 15 | class POP { |
||
| 16 | |||
| 17 | /** |
||
| 18 | * Email regular expression. |
||
| 19 | */ |
||
| 20 | const EMAIL_REGEX = '/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}/i'; |
||
| 21 | |||
| 22 | /** |
||
| 23 | * Instance of the connection to the POP server. |
||
| 24 | * |
||
| 25 | * @var resource |
||
| 26 | */ |
||
| 27 | public $connection = null; |
||
| 28 | |||
| 29 | /** |
||
| 30 | * List of the acceptable for a bounce emails. |
||
| 31 | * |
||
| 32 | * @var array |
||
| 33 | */ |
||
| 34 | public $bouncedWhiteList = []; |
||
| 35 | |||
| 36 | /** |
||
| 37 | * List of the acceptable for a bounce email domains. |
||
| 38 | * |
||
| 39 | * @var array |
||
| 40 | */ |
||
| 41 | public $bouncedWhiteDomains = []; |
||
| 42 | |||
| 43 | /** |
||
| 44 | * Open connection to POP server. |
||
| 45 | * |
||
| 46 | * @param string $host POP server host (default: localhost). |
||
| 47 | * @return int $port POP server port (default: 110) |
||
| 48 | * @param string $username User name. |
||
| 49 | * @param string $password User password. |
||
| 50 | * |
||
| 51 | * @return resource Connection to the POP server or throw POPServerException |
||
| 52 | * @throws POPServerException |
||
| 53 | */ |
||
| 54 | public function open($host = "localhost", $port = 110, $username = "", $password = "") { |
||
| 55 | $sock = fsockopen($host, $port); |
||
| 56 | |||
| 57 | if ($sock) { |
||
| 58 | fgets($sock, 1024); |
||
| 59 | |||
| 60 | // Connection accepted |
||
| 61 | fwrite($sock, "USER " . $username . "\r\n"); |
||
| 62 | $userresponse = fgets($sock, 1024); |
||
| 63 | if ($userresponse[0] == "+") { // User accepted |
||
| 64 | fwrite($sock, "PASS " . $password . "\r\n"); |
||
| 65 | $passresponse = fgets($sock, 1024); |
||
| 66 | if ($passresponse[0] != "+") { // Wrong password |
||
| 67 | $passresponse = str_replace("\r", "", str_replace("\n", "", $passresponse)); |
||
|
0 ignored issues
–
show
|
|||
| 68 | |||
| 69 | throw new POPServerException( |
||
| 70 | "Authentication not accepted. Incorrect password.", 1 |
||
| 71 | ); |
||
| 72 | } |
||
| 73 | } else { // Invalid username |
||
| 74 | throw new POPServerException( |
||
| 75 | "Username '" . $username . "' not accepted.", 1 |
||
| 76 | ); |
||
| 77 | } |
||
| 78 | } else { |
||
| 79 | throw new POPServerException( |
||
| 80 | "Unable to Connect to " . $host . ". Network Problems could be responsible.", 2 |
||
| 81 | ); |
||
| 82 | } |
||
| 83 | $this->connection = $sock; |
||
| 84 | |||
| 85 | return $sock; |
||
| 86 | } |
||
| 87 | |||
| 88 | /** |
||
| 89 | * Close connection to the POP server. |
||
| 90 | */ |
||
| 91 | public function close() { |
||
| 92 | fwrite($this->connection, "QUIT\r\n"); |
||
| 93 | $quitresponse = fgets($this->connection, 1024); |
||
|
0 ignored issues
–
show
$quitresponse 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 Loading history...
|
|||
| 94 | $quitresponse = ""; |
||
|
0 ignored issues
–
show
$quitresponse 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 Loading history...
|
|||
| 95 | fclose($this->connection); |
||
| 96 | } |
||
| 97 | |||
| 98 | /** |
||
| 99 | * Delete message from POP server. |
||
| 100 | * |
||
| 101 | * @return int $messageId Id of the message. |
||
| 102 | * |
||
| 103 | * @return string Response string. |
||
| 104 | */ |
||
| 105 | public function delete($messageId) { |
||
| 106 | fwrite($this->connection, "DELE $messageId\r\n"); |
||
| 107 | |||
| 108 | return fgets($this->connection, 1024); |
||
| 109 | } |
||
| 110 | |||
| 111 | /** |
||
| 112 | * Count messages in POP server. |
||
| 113 | * |
||
| 114 | * @return type |
||
| 115 | */ |
||
| 116 | public function countMessages() { |
||
| 117 | fwrite($this->connection, "STAT\r\n"); |
||
| 118 | $statresponse = fgets($this->connection, 1024); |
||
| 119 | $avar = explode(" ", $statresponse); |
||
| 120 | |||
| 121 | return (int)$avar[1]; |
||
| 122 | } |
||
| 123 | |||
| 124 | /** |
||
| 125 | * Return message header. |
||
| 126 | * |
||
| 127 | * @return int $messageNumber Number of the message. |
||
| 128 | * |
||
| 129 | * @return string |
||
| 130 | */ |
||
| 131 | public function messageHeader($messageNumber) { |
||
| 132 | fwrite($this->connection, "TOP $messageNumber 0\r\n"); |
||
| 133 | $buffer = ""; |
||
| 134 | $headerReceived = 0; |
||
| 135 | while ($headerReceived == 0) { |
||
| 136 | $temp = fgets($this->connection, 1024); |
||
| 137 | $buffer .= $temp; |
||
| 138 | if ($temp == ".\r\n") { |
||
| 139 | $headerReceived = 1; |
||
| 140 | } |
||
| 141 | } |
||
| 142 | |||
| 143 | return $buffer; |
||
| 144 | } |
||
| 145 | |||
| 146 | /** |
||
| 147 | * Return parsed message header. |
||
| 148 | * |
||
| 149 | * @return int $messageNumber Number of the message. |
||
| 150 | * |
||
| 151 | * @return array |
||
| 152 | */ |
||
| 153 | public function getParsedMessageHeader($messageNumber) { |
||
| 154 | return $this->parseHeader( |
||
| 155 | $this->messageHeader($messageNumber) |
||
| 156 | ); |
||
| 157 | } |
||
| 158 | |||
| 159 | /** |
||
| 160 | * Return message by number. |
||
| 161 | * |
||
| 162 | * @return int $messageNumber Number of the message |
||
| 163 | * |
||
| 164 | * @return string |
||
| 165 | */ |
||
| 166 | public function getMessage($messageNumber) { |
||
| 167 | fwrite($this->connection, "RETR $messageNumber\r\n"); |
||
| 168 | $headerReceived = 0; |
||
| 169 | $buffer = ""; |
||
| 170 | while ($headerReceived == 0) { |
||
| 171 | $temp = fgets($this->connection, 1024); |
||
| 172 | $buffer .= $temp; |
||
| 173 | if (substr($buffer, 0, 4) === '-ERR') { |
||
| 174 | return false; |
||
| 175 | } |
||
| 176 | if ($temp == ".\r\n") { |
||
| 177 | $headerReceived = 1; |
||
| 178 | } |
||
| 179 | } |
||
| 180 | |||
| 181 | return $buffer; |
||
| 182 | } |
||
| 183 | |||
| 184 | /** |
||
| 185 | * Return list of the messages in the POP server mail box. |
||
| 186 | * |
||
| 187 | * @return array<string> |
||
| 188 | */ |
||
| 189 | public function getMessages() { |
||
| 190 | $messages = []; |
||
| 191 | |||
| 192 | for ($i = 1; ; $i++) { |
||
| 193 | $message = $this->getMessage($i); |
||
| 194 | if ($message === false) { |
||
| 195 | break; |
||
| 196 | } |
||
| 197 | |||
| 198 | $messages[] = $message; |
||
| 199 | } |
||
| 200 | |||
| 201 | return $messages; |
||
| 202 | } |
||
| 203 | |||
| 204 | /** |
||
| 205 | * Return list of bounced e-mail addresses. |
||
| 206 | * |
||
| 207 | * @return array<string> |
||
| 208 | */ |
||
| 209 | public function getBouncedEmails($delete = true, $number = null) { |
||
| 210 | $emails = []; |
||
| 211 | |||
| 212 | for ($i = 1; (is_null($number) ? true : $i <= $number); $i++) { |
||
| 213 | $message = $this->getMessage($i); |
||
| 214 | if ($message !== false) { |
||
| 215 | $markers = [ |
||
| 216 | 'The following address(es) failed:', |
||
| 217 | 'Delivery to the following recipients failed permanently:', |
||
| 218 | 'Delivery to the following recipients failed.', |
||
| 219 | 'Delivery to the following recipient has been delayed:', |
||
| 220 | 'The following message to <', |
||
| 221 | 'This is a permanent error; I\'ve given up. Sorry it didn\'t work out.', |
||
| 222 | 'I\'m sorry to have to inform you that your message could not', |
||
| 223 | 'This Message was undeliverable due to the following reason:', |
||
| 224 | 'Delivery has failed to these recipients or groups:', |
||
| 225 | '------Transcript of session follows -------', |
||
| 226 | 'Sorry, we were unable to deliver your message to the following address.', |
||
| 227 | 'Your message cannot be delivered to the following recipients:', |
||
| 228 | 'We have tried to deliver your message, but it was rejected by the recipient', |
||
| 229 | 'These recipients of your message have been processed by the mail server:' |
||
| 230 | ]; |
||
| 231 | $failSignaturePos = false; |
||
| 232 | for ($q = 0; $failSignaturePos === false && $q < count($markers); $q++) { |
||
| 233 | $failSignaturePos = strpos($message, $markers[$q]); |
||
| 234 | } |
||
| 235 | |||
| 236 | $endSignaturePos = strpos($message, '--', $failSignaturePos); //End Position |
||
| 237 | View Code Duplication | if ($failSignaturePos === false/* || $endSignaturePos === false*/) { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across 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...
Unused Code
Comprehensibility
introduced
by
38% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. Loading history...
|
|||
| 238 | /*if ($delete) { |
||
|
0 ignored issues
–
show
Unused Code
Comprehensibility
introduced
by
71% of this comment could be valid code. Did you maybe forget this after debugging?
Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it. The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production. This check looks for comments that seem to be mostly valid code and reports them. Loading history...
|
|||
| 239 | $this->delete($i); |
||
| 240 | }*/ |
||
| 241 | continue; |
||
| 242 | } else { |
||
| 243 | if ($endSignaturePos === false || $endSignaturePos <= $failSignaturePos) { |
||
| 244 | $endSignaturePos = strlen($message); |
||
| 245 | } |
||
| 246 | preg_match_all( |
||
| 247 | self::EMAIL_REGEX, substr($message, $failSignaturePos, $endSignaturePos - $failSignaturePos), $emailData |
||
| 248 | ); |
||
| 249 | |||
| 250 | $emails = $this->filterBouncedEmails($emailData); |
||
|
0 ignored issues
–
show
It seems like
$emailData can also be of type null; however, Asymptix\mail\POP::filterBouncedEmails() does only seem to accept array, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
|
|||
| 251 | |||
| 252 | if ($delete) { |
||
| 253 | $this->delete($i); |
||
| 254 | } |
||
| 255 | } |
||
| 256 | } else { |
||
| 257 | break; |
||
| 258 | } |
||
| 259 | } |
||
| 260 | |||
| 261 | return array_unique($emails); |
||
| 262 | } |
||
| 263 | |||
| 264 | /** |
||
| 265 | * Return list of e-mail addresses except white lists. |
||
| 266 | * |
||
| 267 | * @return array<string> |
||
| 268 | */ |
||
| 269 | public function getEmails($delete = true, $number = null) { |
||
| 270 | $emails = []; |
||
| 271 | |||
| 272 | for ($i = 1; (is_null($number) ? true : $i <= $number); $i++) { |
||
| 273 | $message = $this->getMessage($i); |
||
| 274 | View Code Duplication | if ($message !== false) { |
|
|
0 ignored issues
–
show
This code seems to be duplicated across 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...
|
|||
| 275 | $failSignaturePos = 0; |
||
| 276 | $endSignaturePos = strlen($message); |
||
| 277 | |||
| 278 | preg_match_all( |
||
| 279 | self::EMAIL_REGEX, substr($message, $failSignaturePos, $endSignaturePos - $failSignaturePos), $emailData |
||
| 280 | ); |
||
| 281 | |||
| 282 | $emails = $this->filterBouncedEmails($emailData); |
||
|
0 ignored issues
–
show
It seems like
$emailData can also be of type null; however, Asymptix\mail\POP::filterBouncedEmails() does only seem to accept array, maybe add an additional type check?
If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check: /**
* @return array|string
*/
function returnsDifferentValues($x) {
if ($x) {
return 'foo';
}
return array();
}
$x = returnsDifferentValues($y);
if (is_array($x)) {
// $x is an array.
}
If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue. Loading history...
|
|||
| 283 | |||
| 284 | if ($delete) { |
||
| 285 | $this->delete($i); |
||
| 286 | } |
||
| 287 | } else { |
||
| 288 | break; |
||
| 289 | } |
||
| 290 | } |
||
| 291 | |||
| 292 | return array_unique($emails); |
||
| 293 | } |
||
| 294 | |||
| 295 | /** |
||
| 296 | * Returns only bounced e-mails from matches. |
||
| 297 | * |
||
| 298 | * @param array $emailData Matches array after preg_math_all funciton. |
||
| 299 | * |
||
| 300 | * @return array<string> List of bounced e-mails. |
||
| 301 | */ |
||
| 302 | private function filterBouncedEmails($emailData) { |
||
| 303 | $emails = []; |
||
| 304 | |||
| 305 | if (isset($emailData[0])) { |
||
| 306 | if (is_array($emailData[0])) { |
||
| 307 | foreach ($emailData[0] as $email) { |
||
| 308 | if ($this->isBouncedEmail($email)) { |
||
| 309 | $emails[] = $email; |
||
| 310 | } |
||
| 311 | } |
||
| 312 | } else { |
||
| 313 | $email = $emailData[0]; |
||
| 314 | if ($this->isBouncedEmail($email)) { |
||
| 315 | $emails[] = $email; |
||
| 316 | } |
||
| 317 | } |
||
| 318 | } |
||
| 319 | |||
| 320 | return $emails; |
||
| 321 | } |
||
| 322 | |||
| 323 | /** |
||
| 324 | * Detects if email is bounced. |
||
| 325 | * |
||
| 326 | * @param string $email Email address. |
||
| 327 | * |
||
| 328 | * @return bool |
||
| 329 | */ |
||
| 330 | private function isBouncedEmail($email) { |
||
| 331 | $email = trim($email); |
||
| 332 | if (!empty($email)) { |
||
| 333 | if (in_array($email, $this->bouncedWhiteList)) { |
||
| 334 | return false; |
||
| 335 | } |
||
| 336 | $domain = substr(strrchr($email, "@"), 1); |
||
| 337 | if (in_array($domain, $this->bouncedWhiteDomains)) { |
||
| 338 | return false; |
||
| 339 | } |
||
| 340 | |||
| 341 | return true; |
||
| 342 | } |
||
| 343 | |||
| 344 | return false; |
||
| 345 | } |
||
| 346 | |||
| 347 | /** |
||
| 348 | * Parse message header. |
||
| 349 | * |
||
| 350 | * @param string $header Header of the message. |
||
| 351 | * |
||
| 352 | * @return array |
||
| 353 | */ |
||
| 354 | public function parseHeader($header) { |
||
| 355 | $avar = explode("\n", $header); |
||
| 356 | $len = count($avar); |
||
| 357 | $ret = $L2 = $L3 = null; |
||
|
0 ignored issues
–
show
$L3 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 Loading history...
$L2 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 Loading history...
|
|||
| 358 | for ($i = 0; $i < $len; $i++) { |
||
| 359 | if (isset($avar[$i]) && isset($avar[$i][0]) && isset($avar[$i][1]) && isset($avar[$i][2])) { |
||
| 360 | $L2 = $avar[$i][0] . $avar[$i][1]; |
||
| 361 | $L3 = $avar[$i][0] . $avar[$i][1] . $avar[$i][2]; |
||
| 362 | if ($L2 != " " && $L3 != "Rec" && $L2 != "") { |
||
| 363 | $avar2 = explode(":", $avar[$i]); |
||
| 364 | $temp = str_replace("$avar2[0]:", "", $avar[$i]); |
||
| 365 | $ret[$avar2[0]] = $temp; |
||
| 366 | } |
||
| 367 | } |
||
| 368 | } |
||
| 369 | |||
| 370 | return $ret; |
||
| 371 | } |
||
| 372 | |||
| 373 | /** |
||
| 374 | * Get a unique-id listing for one or all messages. |
||
| 375 | * |
||
| 376 | * @return array |
||
| 377 | */ |
||
| 378 | public function uniqueListing() { |
||
| 379 | fwrite($this->connection, "UIDL\r\n"); |
||
| 380 | $response = ""; |
||
| 381 | |||
| 382 | while (true) { |
||
| 383 | $response .= fgets($this->connection, 1024); |
||
| 384 | if (substr($response, -3) === ".\r\n") { |
||
| 385 | $response = substr($response, 0, strlen($response) - 3); //the ".\r\n" removed |
||
| 386 | break; |
||
| 387 | } |
||
| 388 | } |
||
| 389 | $em = explode("\r\n", $response); |
||
| 390 | $em2 = []; |
||
| 391 | foreach ($em as $q) { |
||
| 392 | if (strpos($q, ' ') !== false) { |
||
| 393 | $t = explode(' ', $q); |
||
| 394 | $em2[] = $t[1]; |
||
| 395 | } |
||
| 396 | } |
||
| 397 | |||
| 398 | return $em2; |
||
| 399 | } |
||
| 400 | } |
||
| 401 | |||
| 402 | class POPServerException extends \Exception {} |
||
|
0 ignored issues
–
show
|
|||
| 403 |
This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.
Both the
$myVarassignment in line 1 and the$higherassignment in line 2 are dead. The first because$myVaris never used and the second because$higheris always overwritten for every possible time line.