2016-12-22 3 views
1

Попытка осуществить временный обходной путь, чтобы справиться с этой странной SwiftMailer ошибка:PHP SwiftMailer StringReplacementFilter ошибка обходной

https://github.com/swiftmailer/swiftmailer/issues/762

При чтении файла, который имеет длину ровно п * 8192 байт (п> = 1), последнее значение> $ байтов - это пустая строка, которая вызывает ошибку.

@ комментарий raffomania на GitHub:

мы обнаружили, что следующая подстройка AbstractFilterableInputStream.write бы решить эту проблему для нас:

public function write($bytes) 
{ 
    $this->_writeBuffer .= $bytes; 
    if (empty($this->_writeBuffer)) { 
     return; 
    } 
    foreach ($this->_filters as $filter) { 
     if ($filter->shouldBuffer($this->_writeBuffer)) { 
      return; 
     } 
    } 
    $this->_doWrite($this->_writeBuffer); 

    return ++$this->_sequence; 
} 

Я хотел бы расширить класса AbstractFilterableInputStream и вызывать этот модифицированный метод записи, когда AbstractFilterableInputStream вызывается SwiftMailer.

Я использую раму Laravel.

ответ

1

Лучший способ решить эту проблему - развернуть и зафиксировать swiftmailer, и вы используете свою собственную разветвленную версию swiftmailer. Однако, если вы не хотите этого делать, это исправление довольно продолжительное, но оно должно работать. Дать ему шанс. Если есть какие-либо вопросы, дайте мне знать.

1. Создать app/Mail/CustomFileByteStream.php: У этой версии есть write.

<?php 

namespace App\Mail; 

/** 
* Allows reading and writing of bytes to and from a file. 
* 
* @author Chris Corbyn 
*/ 
class CustomFileByteStream extends \Swift_ByteStream_FileByteStream 
{ 
    public function write($bytes) 
    { 
     $this->_writeBuffer .= $bytes; 
     if (empty($this->_writeBuffer)) { 
      return; 
     } 
     foreach ($this->_filters as $filter) { 
      if ($filter->shouldBuffer($this->_writeBuffer)) { 
       return; 
      } 
     } 
     $this->_doWrite($this->_writeBuffer); 

     return ++$this->_sequence; 
    } 
} 

2. Создание app/Mail/CustomSwiftAttachment.php: Так что он использует пользовательские FileByteStream

<?php 

namespace App\Mail; 

/** 
* Attachment class for attaching files to a {@link Swift_Mime_Message}. 
* 
* @author Chris Corbyn 
*/ 
class CustomSwiftAttachment extends \Swift_Attachment 
{ 
    /** 
    * Create a new Attachment from a filesystem path. 
    * 
    * @param string $path 
    * @param string $contentType optional 
    * 
    * @return Swift_Mime_Attachment 
    */ 
    public static function fromPath($path, $contentType = null) 
    { 
     return self::newInstance()->setFile(
      new CustomFileByteStream($path), 
      $contentType 
      ); 
    } 
} 

3. Создание app/Mail/CustomSwiftImage.php: Так что он использует обычай FileByteStream

<?php 

namespace App\Mail; 

/** 
* An image, embedded in a multipart message. 
* 
* @author Chris Corbyn 
*/ 
class CustomSwiftImage extends \Swift_Image 
{ 
    /** 
    * Create a new Image from a filesystem path. 
    * 
    * @param string $path 
    * 
    * @return Swift_Image 
    */ 
    public static function fromPath($path) 
    { 
     $image = self::newInstance()->setFile(
      new CustomFileByteStream($path) 
      ); 

     return $image; 
    } 
} 

4. Создание app/Mail/Message.php: Так что он использует свой собственный пользовательский Swift_Image и Swift_Attachment

<?php 

namespace App\Mail; 

use Illuminate\Mail\Message as DefaultMessage; 

class Message extends DefaultMessage 
{ 
    /** 
    * Create a Swift Attachment instance. 
    * 
    * @param string $file 
    * @return CustomSwiftAttachment 
    */ 
    protected function createAttachmentFromPath($file) 
    { 
     return CustomSwiftAttachment::fromPath($file); 
    } 

    /** 
    * Embed a file in the message and get the CID. 
    * 
    * @param string $file 
    * @return string 
    */ 
    public function embed($file) 
    { 
     return $this->swift->embed(CustomSwiftImage::fromPath($file)); 
    } 
} 

5. Создание app/Mail/Mailer.php: Так что он использует пользовательский класс Message

<?php 

namespace App\Mail; 

use Swift_Message; 
use Illuminate\Mail\Mailer as DefaultMailer; 

class Mailer extends DefaultMailer 
{ 
    /** 
    * Create a new message instance. Notice this is complete replacement of parent's version. 
    * We uses our own "Message" class instead of theirs. 
    * 
    * @return \Illuminate\Mail\Message 
    */ 
    protected function createMessage() 
    { 
     $message = new Message(new Swift_Message); 

     // If a global from address has been specified we will set it on every message 
     // instances so the developer does not have to repeat themselves every time 
     // they create a new message. We will just go ahead and push the address. 
     if (! empty($this->from['address'])) { 
      $message->from($this->from['address'], $this->from['name']); 
     } 

     return $message; 
    } 
} 

6. Создать app/Mail/MailServiceProvider.php: Поэтому он использует ваш пользовательский номер Mailer класс

<?php 

namespace App\Mail; 

use Illuminate\Mail\MailServiceProvider as DefaultMailServiceProvider; 
use App\Mail\Mailer; 

/** 
* This mail service provider is almost identical with the illuminate version, with the exception that 
* we are hijacking with our own Message class 
*/ 
class MailServiceProvider extends DefaultMailServiceProvider 
{ 
    /** 
    * Complete replacement of parent register class so we can 
    * overwrite the use of mailer class. Notice the "Mailer" class is points to our own 
    * version of mailer, so we can hijack the message class. 
    * 
    * @return void 
    */ 
    public function register() 
    { 
     $this->registerSwiftMailer(); 

     $this->app->singleton('mailer', function ($app) { 
      // Once we have create the mailer instance, we will set a container instance 
      // on the mailer. This allows us to resolve mailer classes via containers 
      // for maximum testability on said classes instead of passing Closures. 
      $mailer = new Mailer(
       $app['view'], $app['swift.mailer'], $app['events'] 
      ); 

      $this->setMailerDependencies($mailer, $app); 

      // If a "from" address is set, we will set it on the mailer so that all mail 
      // messages sent by the applications will utilize the same "from" address 
      // on each one, which makes the developer's life a lot more convenient. 
      $from = $app['config']['mail.from']; 

      if (is_array($from) && isset($from['address'])) { 
       $mailer->alwaysFrom($from['address'], $from['name']); 
      } 

      $to = $app['config']['mail.to']; 

      if (is_array($to) && isset($to['address'])) { 
       $mailer->alwaysTo($to['address'], $to['name']); 
      } 

      return $mailer; 
     }); 
    } 
} 

7.Редактировать config/app.php

  • Закомментируйте Illuminate\Mail\MailServiceProvider::class,
  • Добавьте это ниже линии выше App\Mail\MailServiceProvider::class,

Так что это будет использовать пользовательские MailServiceProvider. В любой момент времени, если вы хотите отменить это, просто удалите все файлы выше и отмените это редактирование.


Вызов последовательности:

enter image description here

Так вот вы идете. Это должно угодить MailServiceProvider, чтобы использовать свой собственный Swift_ByteStream_FileByteStream. Надеюсь, никаких опечаток!

+0

Невероятное спасибо и так много! Сначала я попробую предложить использовать свою собственную вилку, но другое исправление также помогает понять, как работают классы. Спасибо снова супер полезно :) – sombreptile

+0

Все в порядке, вот как я сделал, чтобы захватить одну из функций. Я просто копировал и вставлял его из своего проекта :) –