vendor/monolog/monolog/src/Monolog/Handler/StreamHandler.php line 24

Open in your IDE?
  1. <?php
  2. /*
  3.  * This file is part of the Monolog package.
  4.  *
  5.  * (c) Jordi Boggiano <j.boggiano@seld.be>
  6.  *
  7.  * For the full copyright and license information, please view the LICENSE
  8.  * file that was distributed with this source code.
  9.  */
  10. namespace Monolog\Handler;
  11. use Monolog\Logger;
  12. use Monolog\Utils;
  13. /**
  14.  * Stores to any stream resource
  15.  *
  16.  * Can be used to store into php://stderr, remote and local files, etc.
  17.  *
  18.  * @author Jordi Boggiano <j.boggiano@seld.be>
  19.  */
  20. class StreamHandler extends AbstractProcessingHandler
  21. {
  22.     /** @private 512KB */
  23.     const CHUNK_SIZE 524288;
  24.     /** @var resource|null */
  25.     protected $stream;
  26.     protected $url;
  27.     private $errorMessage;
  28.     protected $filePermission;
  29.     protected $useLocking;
  30.     private $dirCreated;
  31.     /**
  32.      * @param resource|string $stream
  33.      * @param int             $level          The minimum logging level at which this handler will be triggered
  34.      * @param bool            $bubble         Whether the messages that are handled can bubble up the stack or not
  35.      * @param int|null        $filePermission Optional file permissions (default (0644) are only for owner read/write)
  36.      * @param bool            $useLocking     Try to lock log file before doing any writes
  37.      *
  38.      * @throws \Exception                If a missing directory is not buildable
  39.      * @throws \InvalidArgumentException If stream is not a resource or string
  40.      */
  41.     public function __construct($stream$level Logger::DEBUG$bubble true$filePermission null$useLocking false)
  42.     {
  43.         parent::__construct($level$bubble);
  44.         if (is_resource($stream)) {
  45.             $this->stream $stream;
  46.             $this->streamSetChunkSize();
  47.         } elseif (is_string($stream)) {
  48.             $this->url Utils::canonicalizePath($stream);
  49.         } else {
  50.             throw new \InvalidArgumentException('A stream must either be a resource or a string.');
  51.         }
  52.         $this->filePermission $filePermission;
  53.         $this->useLocking $useLocking;
  54.     }
  55.     /**
  56.      * {@inheritdoc}
  57.      */
  58.     public function close()
  59.     {
  60.         if ($this->url && is_resource($this->stream)) {
  61.             fclose($this->stream);
  62.         }
  63.         $this->stream null;
  64.         $this->dirCreated null;
  65.     }
  66.     /**
  67.      * Return the currently active stream if it is open
  68.      *
  69.      * @return resource|null
  70.      */
  71.     public function getStream()
  72.     {
  73.         return $this->stream;
  74.     }
  75.     /**
  76.      * Return the stream URL if it was configured with a URL and not an active resource
  77.      *
  78.      * @return string|null
  79.      */
  80.     public function getUrl()
  81.     {
  82.         return $this->url;
  83.     }
  84.     /**
  85.      * {@inheritdoc}
  86.      */
  87.     protected function write(array $record)
  88.     {
  89.         if (!is_resource($this->stream)) {
  90.             if (null === $this->url || '' === $this->url) {
  91.                 throw new \LogicException('Missing stream url, the stream can not be opened. This may be caused by a premature call to close().');
  92.             }
  93.             $this->createDir();
  94.             $this->errorMessage null;
  95.             set_error_handler(array($this'customErrorHandler'));
  96.             $this->stream fopen($this->url'a');
  97.             if ($this->filePermission !== null) {
  98.                 @chmod($this->url$this->filePermission);
  99.             }
  100.             restore_error_handler();
  101.             if (!is_resource($this->stream)) {
  102.                 $this->stream null;
  103.                 throw new \UnexpectedValueException(sprintf('The stream or file "%s" could not be opened in append mode: '.$this->errorMessage$this->url));
  104.             }
  105.             $this->streamSetChunkSize();
  106.         }
  107.         if ($this->useLocking) {
  108.             // ignoring errors here, there's not much we can do about them
  109.             flock($this->streamLOCK_EX);
  110.         }
  111.         $this->streamWrite($this->stream$record);
  112.         if ($this->useLocking) {
  113.             flock($this->streamLOCK_UN);
  114.         }
  115.     }
  116.     /**
  117.      * Write to stream
  118.      * @param resource $stream
  119.      * @param array $record
  120.      */
  121.     protected function streamWrite($stream, array $record)
  122.     {
  123.         fwrite($stream, (string) $record['formatted']);
  124.     }
  125.     protected function streamSetChunkSize()
  126.     {
  127.         if (version_compare(PHP_VERSION'5.4.0''>=')) {
  128.             return stream_set_chunk_size($this->streamself::CHUNK_SIZE);
  129.         }
  130.         return false;
  131.     }
  132.     private function customErrorHandler($code$msg)
  133.     {
  134.         $this->errorMessage preg_replace('{^(fopen|mkdir)\(.*?\): }'''$msg);
  135.     }
  136.     /**
  137.      * @param string $stream
  138.      *
  139.      * @return null|string
  140.      */
  141.     private function getDirFromStream($stream)
  142.     {
  143.         $pos strpos($stream'://');
  144.         if ($pos === false) {
  145.             return dirname($stream);
  146.         }
  147.         if ('file://' === substr($stream07)) {
  148.             return dirname(substr($stream7));
  149.         }
  150.         return null;
  151.     }
  152.     private function createDir()
  153.     {
  154.         // Do not try to create dir if it has already been tried.
  155.         if ($this->dirCreated) {
  156.             return;
  157.         }
  158.         $dir $this->getDirFromStream($this->url);
  159.         if (null !== $dir && !is_dir($dir)) {
  160.             $this->errorMessage null;
  161.             set_error_handler(array($this'customErrorHandler'));
  162.             $status mkdir($dir0777true);
  163.             restore_error_handler();
  164.             if (false === $status && !is_dir($dir)) {
  165.                 throw new \UnexpectedValueException(sprintf('There is no existing directory at "%s" and its not buildable: '.$this->errorMessage$dir));
  166.             }
  167.         }
  168.         $this->dirCreated true;
  169.     }
  170. }