Skip to content
This repository has been archived by the owner on Nov 17, 2021. It is now read-only.

Commit

Permalink
bug #1355 PHP 8.1 Support (driesvints)
Browse files Browse the repository at this point in the history
This PR was squashed before being merged into the 6.2-dev branch.

Discussion
----------

PHP 8.1 Support

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| Doc update?   | no
| BC breaks?    | no
| Deprecations? |no
| Fixed tickets |
| License       | MIT

This PR updates SwiftMailer to be compatible with PHP 8.1. Additionally, I've migrated the Travis build to GitHub Actions. More tests are being run now thanks to this.

The reason why I sent this in is because we'll need this to offer PHP 8.1 support on the mail component in Laravel 8. For the upcoming Laravel 9 release in January 2022 we're switching to Symfony Mailer. I've also manually tested this PR through using the Laravel 8 mail component.

I've tried to go over all the pieces of code that I changed in comments below. Thought that was a bit more useful to review.

Would love to get feedback on this soon as PHP 8.1 is now fast approaching! 🙂

Commits
-------

ee8a1d9 PHP 8.1 Support
  • Loading branch information
fabpot committed Oct 18, 2021
2 parents 2a7fb75 + ee8a1d9 commit bc28df7
Show file tree
Hide file tree
Showing 29 changed files with 158 additions and 97 deletions.
55 changes: 55 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
name: tests

on:
push:
pull_request:

jobs:
linux_tests:
runs-on: ubuntu-20.04

services:
mailcatcher:
image: dockage/mailcatcher:0.7.1
ports:
- 4456:1025

strategy:
fail-fast: true
matrix:
php: ['7.0', '7.1', '7.2', '7.3', '7.4', '8.0', '8.1']

name: PHP ${{ matrix.php }}

steps:
- name: Checkout code
uses: actions/checkout@v2

- name: Setup PHP
uses: shivammathur/setup-php@v2
with:
php-version: ${{ matrix.php }}
extensions: dom, curl, libxml, mbstring, zip, intl
tools: composer:v2
coverage: none

- name: Prepare test config files
run: |
cp tests/acceptance.conf.php.default tests/acceptance.conf.php
cp tests/smoke.conf.php.default tests/smoke.conf.php
- name: Require Symfony PHPUnit Bridge 5.4 for PHP 8.1
if: ${{ matrix.php >= 8.1 }}
run: composer require symfony/phpunit-bridge:^5.4 --dev --prefer-dist --no-interaction --no-progress

- name: Install dependencies
uses: nick-invision/retry@v1
with:
timeout_minutes: 5
max_attempts: 5
command: composer update --prefer-stable --prefer-dist --no-interaction --no-progress

- name: Execute tests
run: vendor/bin/simple-phpunit --verbose
env:
SYMFONY_PHPUNIT_REMOVE_RETURN_TYPEHINT: 1
30 changes: 0 additions & 30 deletions .travis.yml

This file was deleted.

6 changes: 4 additions & 2 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
},
"require-dev": {
"mockery/mockery": "^1.0",
"symfony/phpunit-bridge": "^4.4|^5.0"
"symfony/phpunit-bridge": "^4.4|^5.4"
},
"suggest": {
"ext-intl": "Needed to support internationalized email addresses"
Expand All @@ -38,5 +38,7 @@
"branch-alias": {
"dev-master": "6.2-dev"
}
}
},
"minimum-stability": "dev",
"prefer-stable": true
}
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ public function init()
*/
public function getReaderFor($charset)
{
$charset = strtolower(trim($charset));
$charset = strtolower(trim($charset ?? ''));
foreach (self::$map as $pattern => $spec) {
$re = '/^'.$pattern.'$/D';
if (preg_match($re, $charset)) {
Expand Down
2 changes: 1 addition & 1 deletion lib/classes/Swift/Encoder/Base64Encoder.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0)
$maxLineLength = 76;
}

$encodedString = base64_encode($string);
$encodedString = base64_encode($string ?? '');
$firstLine = '';

if (0 != $firstLineOffset) {
Expand Down
2 changes: 1 addition & 1 deletion lib/classes/Swift/Message.php
Original file line number Diff line number Diff line change
Expand Up @@ -224,7 +224,7 @@ protected function saveMessage()
protected function saveHeaders(array $altered)
{
foreach ($altered as $head) {
$lc = strtolower($head);
$lc = strtolower($head ?? '');

if (!isset($this->savedMessage['headers'][$lc])) {
$this->savedMessage['headers'][$lc] = $this->getHeaders()->getAll($head);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStre
}

$remainder = 0;
$base64ReadBufferRemainderBytes = null;
$base64ReadBufferRemainderBytes = '';

// To reduce memory usage, the output buffer is streamed to the input buffer like so:
// Output Stream => base64encode => wrap line length => Input Stream
Expand All @@ -45,7 +45,7 @@ public function encodeByteStream(Swift_OutputByteStream $os, Swift_InputByteStre
} else {
$streamTheseBytes = $base64ReadBufferRemainderBytes.$readBytes;
}
$base64ReadBufferRemainderBytes = null;
$base64ReadBufferRemainderBytes = '';
$bytesLength = \strlen($streamTheseBytes);

if (0 === $bytesLength) { // no data left to encode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public function getName()
*/
public function encodeString($string, $firstLineOffset = 0, $maxLineLength = 0, $charset = 'utf-8')
{
if ('iso-2022-jp' === strtolower($charset)) {
if ('iso-2022-jp' === strtolower($charset ?? '')) {
$old = mb_internal_encoding();
mb_internal_encoding('utf-8');
$newstring = mb_encode_mimeheader($string, $charset, $this->getName(), "\r\n");
Expand Down
20 changes: 15 additions & 5 deletions lib/classes/Swift/Mime/Headers/AbstractHeader.php
Original file line number Diff line number Diff line change
Expand Up @@ -309,7 +309,7 @@ protected function getEncodableWordTokens($string)

$encodedToken = '';
// Split at all whitespace boundaries
foreach (preg_split('~(?=[\t ])~', $string) as $token) {
foreach (preg_split('~(?=[\t ])~', $string ?? '') as $token) {
if ($this->tokenNeedsEncoding($token)) {
$encodedToken .= $token;
} else {
Expand Down Expand Up @@ -354,10 +354,10 @@ protected function getTokenAsEncodedWord($token, $firstLineOffset = 0)
$encodedTextLines = explode("\r\n",
$this->encoder->encodeString(
$token, $firstLineOffset, 75 - $encodingWrapperLength, $this->charset
)
) ?? ''
);

if ('iso-2022-jp' !== strtolower($this->charset)) {
if ('iso-2022-jp' !== strtolower($this->charset ?? '')) {
// special encoding for iso-2022-jp using mb_encode_mimeheader
foreach ($encodedTextLines as $lineNum => $line) {
$encodedTextLines[$lineNum] = '=?'.$charsetDecl.
Expand All @@ -378,7 +378,7 @@ protected function getTokenAsEncodedWord($token, $firstLineOffset = 0)
*/
protected function generateTokenLines($token)
{
return preg_split('~(\r\n)~', $token, -1, PREG_SPLIT_DELIM_CAPTURE);
return preg_split('~(\r\n)~', $token ?? '', -1, PREG_SPLIT_DELIM_CAPTURE);
}

/**
Expand Down Expand Up @@ -429,7 +429,7 @@ protected function toTokens($string = null)
$tokens = [];

// Generate atoms; split at all invisible boundaries followed by WSP
foreach (preg_split('~(?=[ \t])~', $string) as $token) {
foreach (preg_split('~(?=[ \t])~', $string ?? '') as $token) {
$newTokens = $this->generateTokenLines($token);
foreach ($newTokens as $newToken) {
$tokens[] = $newToken;
Expand Down Expand Up @@ -473,4 +473,14 @@ private function tokensToString(array $tokens)
// Implode with FWS (RFC 2822, 2.2.3)
return implode("\r\n", $headerLines)."\r\n";
}

/**
* Make a deep copy of object.
*/
public function __clone()
{
if ($this->encoder) {
$this->encoder = clone $this->encoder;
}
}
}
2 changes: 1 addition & 1 deletion lib/classes/Swift/Mime/MimePart.php
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ protected function setNestingLevel($level)
/** Encode charset when charset is not utf-8 */
protected function convertString($string)
{
$charset = strtolower($this->getCharset());
$charset = strtolower($this->getCharset() ?? '');
if (!\in_array($charset, ['utf-8', 'iso-8859-1', 'iso-8859-15', ''])) {
return mb_convert_encoding($string, $charset, 'utf-8');
}
Expand Down
3 changes: 2 additions & 1 deletion lib/classes/Swift/Mime/SimpleHeaderFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ public function createTextHeader($name, $value = null)
*/
public function createParameterizedHeader($name, $value = null, $params = [])
{
$header = new Swift_Mime_Headers_ParameterizedHeader($name, $this->encoder, ('content-disposition' == strtolower($name)) ? $this->paramEncoder : null);
$header = new Swift_Mime_Headers_ParameterizedHeader($name, $this->encoder, ('content-disposition' == strtolower($name ?? '')) ? $this->paramEncoder : null);
if (isset($value)) {
$header->setFieldBodyModel($value);
}
Expand Down Expand Up @@ -182,6 +182,7 @@ public function __clone()
{
$this->encoder = clone $this->encoder;
$this->paramEncoder = clone $this->paramEncoder;
$this->addressEncoder = clone $this->addressEncoder;
}

/** Apply the charset to the Header */
Expand Down
24 changes: 12 additions & 12 deletions lib/classes/Swift/Mime/SimpleHeaderSet.php
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ public function addPathHeader($name, $path = null)
*/
public function has($name, $index = 0)
{
$lowerName = strtolower($name);
$lowerName = strtolower($name ?? '');

if (!\array_key_exists($lowerName, $this->headers)) {
return false;
Expand Down Expand Up @@ -181,7 +181,7 @@ public function set(Swift_Mime_Header $header, $index = 0)
*/
public function get($name, $index = 0)
{
$name = strtolower($name);
$name = strtolower($name ?? '');

if (\func_num_args() < 2) {
if ($this->has($name)) {
Expand Down Expand Up @@ -214,7 +214,7 @@ public function getAll($name = null)
return $headers;
}

$lowerName = strtolower($name);
$lowerName = strtolower($name ?? '');
if (!\array_key_exists($lowerName, $this->headers)) {
return [];
}
Expand Down Expand Up @@ -247,7 +247,7 @@ public function listAll()
*/
public function remove($name, $index = 0)
{
$lowerName = strtolower($name);
$lowerName = strtolower($name ?? '');
unset($this->headers[$lowerName][$index]);
}

Expand All @@ -258,7 +258,7 @@ public function remove($name, $index = 0)
*/
public function removeAll($name)
{
$lowerName = strtolower($name);
$lowerName = strtolower($name ?? '');
unset($this->headers[$lowerName]);
}

Expand Down Expand Up @@ -330,13 +330,13 @@ public function __toString()
/** Save a Header to the internal collection */
private function storeHeader($name, Swift_Mime_Header $header, $offset = null)
{
if (!isset($this->headers[strtolower($name)])) {
$this->headers[strtolower($name)] = [];
if (!isset($this->headers[strtolower($name ?? '')])) {
$this->headers[strtolower($name ?? '')] = [];
}
if (!isset($offset)) {
$this->headers[strtolower($name)][] = $header;
$this->headers[strtolower($name ?? '')][] = $header;
} else {
$this->headers[strtolower($name)][$offset] = $header;
$this->headers[strtolower($name ?? '')][$offset] = $header;
}
}

Expand All @@ -349,8 +349,8 @@ private function canSort()
/** uksort() algorithm for Header ordering */
private function sortHeaders($a, $b)
{
$lowerA = strtolower($a);
$lowerB = strtolower($b);
$lowerA = strtolower($a ?? '');
$lowerB = strtolower($b ?? '');
$aPos = \array_key_exists($lowerA, $this->order) ? $this->order[$lowerA] : -1;
$bPos = \array_key_exists($lowerB, $this->order) ? $this->order[$lowerB] : -1;

Expand All @@ -371,7 +371,7 @@ private function sortHeaders($a, $b)
/** Test if the given Header is always displayed */
private function isDisplayed(Swift_Mime_Header $header)
{
return \array_key_exists(strtolower($header->getFieldName()), $this->required);
return \array_key_exists(strtolower($header->getFieldName() ?? ''), $this->required);
}

/** Notify all Headers of the new charset */
Expand Down
2 changes: 1 addition & 1 deletion lib/classes/Swift/Mime/SimpleMimeEntity.php
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,7 @@ private function getNeededChildLevel($child, $compoundLevel)
}

$realLevel = $child->getNestingLevel();
$lowercaseType = strtolower($child->getContentType());
$lowercaseType = strtolower($child->getContentType() ?? '');

if (isset($filter[$realLevel]) && isset($filter[$realLevel][$lowercaseType])) {
return $filter[$realLevel][$lowercaseType];
Expand Down
10 changes: 5 additions & 5 deletions lib/classes/Swift/Plugins/PopBeforeSmtpPlugin.php
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ public function connect()
$this->socket = $socket;

if (false === $greeting = fgets($this->socket)) {
throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to connect to POP3 host [%s]', trim($greeting)));
throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to connect to POP3 host [%s]', trim($greeting ?? '')));
}

$this->assertOk($greeting);
Expand Down Expand Up @@ -205,11 +205,11 @@ public function transportStopped(Swift_Events_TransportChangeEvent $evt)
private function command($command)
{
if (!fwrite($this->socket, $command)) {
throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to write command [%s] to POP3 host', trim($command)));
throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to write command [%s] to POP3 host', trim($command ?? '')));
}

if (false === $response = fgets($this->socket)) {
throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to read from POP3 host after command [%s]', trim($command)));
throw new Swift_Plugins_Pop_Pop3Exception(sprintf('Failed to read from POP3 host after command [%s]', trim($command ?? '')));
}

$this->assertOk($response);
Expand All @@ -220,14 +220,14 @@ private function command($command)
private function assertOk($response)
{
if ('+OK' != substr($response, 0, 3)) {
throw new Swift_Plugins_Pop_Pop3Exception(sprintf('POP3 command failed [%s]', trim($response)));
throw new Swift_Plugins_Pop_Pop3Exception(sprintf('POP3 command failed [%s]', trim($response ?? '')));
}
}

private function getHostString()
{
$host = $this->host;
switch (strtolower($this->crypto)) {
switch (strtolower($this->crypto ?? '')) {
case 'ssl':
$host = 'ssl://'.$host;
break;
Expand Down
Loading

0 comments on commit bc28df7

Please sign in to comment.