/** * Sends the command to the server and reads the response to it. * * @param string|NULL|array $command The command to send (can use printf * style). If NULL, no command is sent * and this just reads a server response. * If it is an array, all items will be * treated like lines of commands and * will be sent to the server while the * response will be read only after all * of them are sent. * @param mixed $args,... Optional printf-like arguments * * @return Response The server response * * @throws InvalidStateException If the communicator is not connected * @throws InvalidArgumentException If printf-like arguments are used for * non-textual command (ie. array command) * @throws IOException If writing or reading over network failed */ public function getResponse($command) { if ($this->connection === NULL) { throw new InvalidStateException('Cannot communicate with SMTP ' . 'server when not connected.'); } if ($command !== NULL) { if (func_num_args() > 1) { if (!is_string($command)) { throw new InvalidArgumentException('Cannot use printf-like arguments to a command which' . ' is not a string!'); } $args = func_get_args(); array_shift($args); $command = vsprintf($command, $args); } if (!is_array($command)) { $command = array($command); } foreach ($command as $line) { //send the command to the server SMTPClient::debug("\n\nCOMMAND: %s\n=======", $line); if (@fwrite($this->connection, $line . self::EOL) === FALSE) { if (@fwrite($this->connection, $line . self::EOL) === FALSE) { throw new IOException('Could not send the command to the ' . 'server: ' . $command); } } } } /* * The reply text may be longer than a single line; in these cases the * complete text must be marked so the SMTP client knows when it can * stop reading the reply. This requires a special format to indicate a * multiple line reply. * * The format for multiline replies requires that every line, except the * last, begin with the reply code, followed immediately by a hyphen, * "-" (also known as minus), followed by text. The last line will * begin with the reply code, followed immediately by <SP>, optionally * some text, and <CRLF>. As noted above, servers SHOULD send the <SP> * if subsequent text is not sent, but clients MUST be prepared for it * to be omitted. * * For example: * * 123-First line * 123-Second line * 123-234 text beginning with numbers * 123 The last line * * In many cases the SMTP client then simply needs to search for a line * beginning with the reply code followed by <SP> or <CRLF> and ignore * all preceding lines. In a few cases, there is important data for the * client in the reply "text". The client will be able to identify * these cases from the current context. */ $response['code'] = ''; $response['text'] = array(); $responsePart = ''; $i = 0; //we fetch lines of the response while ($line = fgets($this->connection, self::MAX_RESPONSE_LENGTH)) { //fgets leaves the CRLF at the end of the string $line = rtrim($line); //blank line shouldn't appear, it indicates nothing more is to //be read if (strlen($line) < 3) { break; } //if we loop a lot of times, something went wrong, so //give up the reading if ($i > self::MAX_RESPONSE_LINES) { throw new InvalidStateException('There was a problem reading server response. The client' . 'could not detect its end.'); } SMTPClient::debug('RESPONSE LINE #%u: %s', ++$i, $line); //first 3 charachters denote the response code $response['code'] = substr($line, 0, 3); //and everything after the 4th character is the response text //note that the response text can be empty, in that case the //response text will be false ( @see substr() ) $response['text'][] = substr($line, 4); //If we encountered a response, where space follows response code, //it is the last line. Other lines have a hyphen (-) instead if (substr($line, 3, 1) == ' ') { break; } } $this->lastResponse = new Response((int) $response['code'], $response['text']); return $this->lastResponse; }