vendor/swiftmailer/lib/classes/Swift/FileSpool.php
changeset 0 7f95f8617b0b
equal deleted inserted replaced
-1:000000000000 0:7f95f8617b0b
       
     1 <?php
       
     2 
       
     3 /*
       
     4  * This file is part of SwiftMailer.
       
     5  * (c) 2009 Fabien Potencier <fabien.potencier@gmail.com>
       
     6  *
       
     7  * For the full copyright and license information, please view the LICENSE
       
     8  * file that was distributed with this source code.
       
     9  */
       
    10 
       
    11 /**
       
    12  * Stores Messages on the filesystem.
       
    13  * @package Swift
       
    14  * @author  Fabien Potencier
       
    15  * @author Xavier De Cock <xdecock@gmail.com>
       
    16  */
       
    17 class Swift_FileSpool extends Swift_ConfigurableSpool
       
    18 {
       
    19   /** The spool directory */
       
    20   private $_path;
       
    21   
       
    22   /**
       
    23    * File WriteRetry Limit
       
    24    * @var int
       
    25    */
       
    26   private $_retryLimit=10;
       
    27   
       
    28   /**
       
    29    * Create a new FileSpool.
       
    30    * @param string $path
       
    31    * @throws Swift_IoException
       
    32    */
       
    33   public function __construct($path)
       
    34   {
       
    35     $this->_path = $path;
       
    36     
       
    37     if (!file_exists($this->_path))
       
    38     {
       
    39       if (!mkdir($this->_path, 0777, true))
       
    40       {
       
    41         throw new Swift_IoException('Unable to create Path ['.$this->_path.']');
       
    42       }
       
    43     }
       
    44   }
       
    45   
       
    46   /**
       
    47    * Tests if this Spool mechanism has started.
       
    48    *
       
    49    * @return boolean
       
    50    */
       
    51   public function isStarted()
       
    52   {
       
    53     return true;
       
    54   }
       
    55   
       
    56   /**
       
    57    * Starts this Spool mechanism.
       
    58    */
       
    59   public function start()
       
    60   {
       
    61   }
       
    62   
       
    63   /**
       
    64    * Stops this Spool mechanism.
       
    65    */
       
    66   public function stop()
       
    67   {
       
    68   }
       
    69   
       
    70   /**
       
    71    * Allow to manage the enqueuing retry limit.
       
    72    * Default, is ten and allows over 64^20 different fileNames 
       
    73    * 
       
    74    * @param integer $limit
       
    75    */
       
    76   public function setRetryLimit($limit)
       
    77   {
       
    78     $this->_retryLimit=$limit;
       
    79   }
       
    80   
       
    81   /**
       
    82    * Queues a message.
       
    83    * @param Swift_Mime_Message $message The message to store
       
    84    * @return boolean
       
    85    * @throws Swift_IoException
       
    86    */
       
    87   public function queueMessage(Swift_Mime_Message $message)
       
    88   {
       
    89     $ser = serialize($message);
       
    90     $fileName=$this->_path.'/'.$this->getRandomString(10);
       
    91     for ($i = 0; $i < $this->_retryLimit; ++$i) 
       
    92     {
       
    93       /* We try an exclusive creation of the file
       
    94        * This is an atomic operation, it avoid locking mechanism
       
    95        */
       
    96       $fp=fopen($fileName.'.message', 'x');
       
    97       if ($fp) 
       
    98       {
       
    99         fwrite($fp, $ser);
       
   100         fclose($fp);
       
   101         
       
   102         return;
       
   103       } 
       
   104       else 
       
   105       {
       
   106         /* The file allready exists, we try a longer fileName
       
   107          */
       
   108         $fileName.=$this->getRandomString(1);
       
   109       }
       
   110     }
       
   111     
       
   112     throw new Swift_IoException('Unable to create a file for enqueuing Message');
       
   113   }
       
   114   
       
   115   /**
       
   116    * Execute a recovery if for anyreason a process is sending for too long
       
   117    * 
       
   118    * @param int $timeout in second Defaults is for very slow smtp responses
       
   119    */
       
   120   public function recover($timeout=900)
       
   121   {
       
   122     foreach (new DirectoryIterator($this->_path) as $file)
       
   123     {
       
   124       $file = $file->getRealPath();
       
   125 
       
   126       if (substr($file, -16)=='.message.sending')
       
   127       {
       
   128         $lockedtime=filectime($file);
       
   129         if ((time()-$lockedtime)>$timeout) 
       
   130         {
       
   131           rename($file, substr($file, 0, -8));
       
   132         }
       
   133       }
       
   134     }    
       
   135   }
       
   136   
       
   137   /**
       
   138    * Sends messages using the given transport instance.
       
   139    *
       
   140    * @param Swift_Transport $transport         A transport instance
       
   141    * @param string[]        &$failedRecipients An array of failures by-reference
       
   142    *
       
   143    * @return int The number of sent emails
       
   144    */
       
   145   public function flushQueue(Swift_Transport $transport, &$failedRecipients = null)
       
   146   {
       
   147     if (!$transport->isStarted())
       
   148     {
       
   149       $transport->start();
       
   150     }
       
   151 
       
   152     $failedRecipients = (array) $failedRecipients;
       
   153     $count = 0;
       
   154     $time = time();
       
   155     foreach (new DirectoryIterator($this->_path) as $file)
       
   156     {
       
   157       $file = $file->getRealPath();
       
   158 
       
   159       if (substr($file, -8) != '.message')
       
   160       {
       
   161         continue;
       
   162       }
       
   163 
       
   164       /* We try a rename, it's an atomic operation, and avoid locking the file */
       
   165       if (rename($file, $file.'.sending')) 
       
   166       {
       
   167         $message = unserialize(file_get_contents($file.'.sending'));
       
   168 
       
   169         $count += $transport->send($message, $failedRecipients);
       
   170 
       
   171         unlink($file.'.sending');
       
   172       }
       
   173       else 
       
   174       {
       
   175         /* This message has just been catched by another process */
       
   176         continue;
       
   177       }
       
   178 
       
   179       if ($this->getMessageLimit() && $count >= $this->getMessageLimit())
       
   180       {
       
   181         break;
       
   182       }
       
   183 
       
   184       if ($this->getTimeLimit() && (time() - $time) >= $this->getTimeLimit())
       
   185       {
       
   186         break;
       
   187       }
       
   188     }
       
   189 
       
   190     return $count;
       
   191   }
       
   192   
       
   193   /**
       
   194    * Returns a random string needed to generate a fileName for the queue.
       
   195    * @param int $count
       
   196    */
       
   197   protected function getRandomString($count) {
       
   198     // This string MUST stay FS safe, avoid special chars
       
   199     $base="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-.";
       
   200     $ret='';
       
   201     $strlen=strlen($base);
       
   202     for ($i=0; $i<$count; ++$i) 
       
   203     {
       
   204       $ret.=$base[((int)rand(0,$strlen-1))];
       
   205     }
       
   206     return $ret;
       
   207   }
       
   208 }