/**
  * Opens a handle to the log file and instantiates a mutex that prevents
  * concurrent writes.
  *
  * @param string $logFile
  * @param string $emailRecipient = null
  * @param Mutex $mutex = null
  * @param boolean $useGZip = null
  */
 public function __construct($logFile, $emailRecipient = null, Mutex $mutex = null, $useGZip = null)
 {
     if (!self::$_registeredSendFunction) {
         /* We want to ensure that emails get sent even if an error takes
         			place that stops the destructor from getting called (e.g. a PHP
         			fatal error). However, we can't register any instance methods as
         			shutdown functions, because it prevents their refcounts from
         			dropping to zero. My solution is to maintain the emails in a
         			static property, and the shutdown function will iterate through any
         			of them with pending content and send them. */
         register_shutdown_function(array(__CLASS__, 'sendEmail'));
     }
     if ($emailRecipient) {
         try {
             // This default subject can be overridden later
             self::$_emails[] = $this->_email = new Email($emailRecipient, 'Automated log message report');
         } catch (EmailException $e) {
             throw new LoggerException('Caught error while initializing email.', null, $e);
         }
     }
     if ($useGZip === null) {
         $useGZip = substr($logFile, -3) == '.gz';
     }
     $this->_useGZip = $useGZip;
     if (!$mutex) {
         try {
             $mutex = new Mutex(__CLASS__);
         } catch (MutexException $e) {
             throw new LoggerException('Unable to instantiate mutex.', null, $e);
         }
     }
     $this->_mutex = $mutex;
     $this->_logFileName = $logFile;
     /* We'll defer the actual opening of the file handle until it's needed.
     		This is mainly due to the fact that appending to a gzip stream appends
     		a gzip header each time, so if we're not going to end up with anything
     		to log, it's better not to even open the handle in the first place.
     		It doesn't really make a difference for uncompressed files, but it's
     		simplest to handle both stream types in the same way. */
     if (!PFXUtils::testWritable($this->_logFileName)) {
         throw new LoggerException($this->_logFileName . ' does not appear to be writable.');
     }
     if ($this->_useGZip) {
         $this->_openFunction = 'gzopen';
         $this->_closeFunction = 'gzclose';
         $this->_writeFunction = 'gzwrite';
     } else {
         $this->_openFunction = 'fopen';
         $this->_closeFunction = 'fclose';
         $this->_writeFunction = 'fwrite';
     }
 }
Exemple #2
0
 /**
  * Performs a Google Analytics query with the given Google\Analytics\IQuery
  * object and attaches the result to the given Email instance. If the email
  * does not yet have a subject, one will be set automatically. If failures
  * took place while running the query (e.g. the query declared a preference
  * for no data sampling and one or more iterations contained sampled data),
  * a message regarding the failure will be appended to the email
  * automatically. If a file path is provided as the fourth argument, the
  * report will be copied to that location in addition to being attached to
  * the email.
  *
  * @param Google\Analytics\IQuery $query
  * @param Google\Analytics\ReportFormatter $formatter
  * @param Email $email
  * @param string $file = null
  */
 public function queryToEmail(IQuery $query, ReportFormatter $formatter, \Email $email, $file = null)
 {
     if ($file && !\PFXUtils::testWritable(dirname($file))) {
         throw new RuntimeException('Cannot write to ' . $file . '.');
     }
     $hasSubject = strlen($email->getSubject()) > 0;
     try {
         $formatter->openTempFile(GOOGLE_ANALYTICS_API_DATA_DIR);
         $exception = null;
         try {
             $this->queryToFile($query, $formatter);
         } catch (FailedIterationsException $e) {
             /* Trap this exception here for now and deliver whatever data
                we can. */
             $exception = $e;
         }
         $bytesWritten = $formatter->getBytesWritten();
         if ($bytesWritten) {
             $tempFile = $formatter->getFileName();
             if ($bytesWritten > GOOGLE_ANALYTICS_API_AUTOZIP_THRESHOLD) {
                 $zip = new \ZipArchive();
                 $tempZip = tempnam(GOOGLE_ANALYTICS_API_DATA_DIR, 'gaz');
                 if ($zip->open($tempZip, \ZipArchive::CREATE) !== true) {
                     throw new RuntimeException('Failed to initialize ZIP archive. Did not ' . 'include the file ' . basename($tempFile) . ' in this message due to its size exceeding ' . GOOGLE_ANALYTICS_API_AUTOZIP_THRESHOLD . ' bytes.');
                 }
                 $zip->addFile($tempFile, 'ga-report.csv');
                 $zip->close();
                 $email->addAttachment($tempZip, 'ga-report.zip');
                 unlink($tempZip);
             } else {
                 $email->addAttachment($tempFile, 'ga-report.csv');
             }
             if ($file && !copy($tempFile, $file)) {
                 throw new RuntimeException('Unable to copy report to ' . $file . '.');
             }
             unlink($tempFile);
         }
         if (!$hasSubject) {
             $email->setSubject($query->getEmailSubject());
             $hasSubject = true;
         }
         if ($exception) {
             throw $exception;
         } elseif (!$bytesWritten) {
             throw new UnderflowException('Google returned no data for this query.');
         }
     } catch (\Exception $e) {
         if (!$hasSubject) {
             /* This should only happen if there is an error affecting the
                report as a whole, not just in one or more of its iterations.
                */
             $email->setSubject('Encountered failure while running ' . $query->getEmailSubject());
         }
         $email->appendMessage($e->getMessage(), true);
     }
 }