af60bb31016a01db9bc1e7bb7533d9c9879ebeb9
[Packages/TYPO3.CMS.git] / typo3 / sysext / core / Classes / Log / Writer / FileWriter.php
1 <?php
2 namespace TYPO3\CMS\Core\Log\Writer;
3
4 /**
5 * This file is part of the TYPO3 CMS project.
6 *
7 * It is free software; you can redistribute it and/or modify it under
8 * the terms of the GNU General Public License, either version 2
9 * of the License, or any later version.
10 *
11 * For the full copyright and license information, please read the
12 * LICENSE.txt file that was distributed with this source code.
13 *
14 * The TYPO3 project - inspiring people to share!
15 */
16
17 use TYPO3\CMS\Core\Utility\GeneralUtility;
18
19 /**
20 * Log writer that writes the log records into a file.
21 *
22 * @author Steffen Gebert <steffen.gebert@typo3.org>
23 * @author Steffen Müller <typo3@t3node.com>
24 * @author Ingo Renner <ingo@typo3.org>
25 */
26 class FileWriter extends AbstractWriter {
27
28 /**
29 * Log file path, relative to PATH_site
30 *
31 * @var string
32 */
33 protected $logFile = '';
34
35 /**
36 * Default log file path
37 *
38 * @var string
39 */
40 protected $defaultLogFile = 'typo3temp/logs/typo3.log';
41
42 /**
43 * Log file handle storage
44 *
45 * To avoid concurrent file handles on a the same file when using several FileWriter instances,
46 * we share the file handles in a static class variable
47 *
48 * @static
49 * @var array
50 */
51 static protected $logFileHandles = array();
52
53 /**
54 * Constructor, opens the log file handle
55 *
56 * @param array $options
57 * @return \TYPO3\CMS\Core\Log\Writer\FileWriter
58 */
59 public function __construct(array $options = array()) {
60 // the parent constructor reads $options and sets them
61 parent::__construct($options);
62 if (empty($options['logFile'])) {
63 $this->setLogFile($this->defaultLogFile);
64 }
65 }
66
67 /**
68 * Destructor, closes the log file handle
69 */
70 public function __destruct() {
71 $this->closeLogFile();
72 }
73
74 /**
75 * Sets the path to the log file.
76 *
77 * @param string $logFile path to the log file, relative to PATH_site
78 * @return \TYPO3\CMS\Core\Log\Writer\WriterInterface
79 * @throws \InvalidArgumentException
80 */
81 public function setLogFile($logFile) {
82
83 // Skip handling if logFile is a stream resource. This is used by unit tests with vfs:// directories
84 if (FALSE === strpos($logFile, '://')) {
85 if (!GeneralUtility::isAllowedAbsPath((PATH_site . $logFile))) {
86 throw new \InvalidArgumentException('Log file path "' . $logFile . '" is not valid!', 1326411176);
87 }
88 $logFile = GeneralUtility::getFileAbsFileName($logFile);
89 }
90 $this->logFile = $logFile;
91 $this->openLogFile();
92
93 return $this;
94 }
95
96 /**
97 * Gets the path to the log file.
98 *
99 * @return string Path to the log file.
100 */
101 public function getLogFile() {
102 return $this->logFile;
103 }
104
105 /**
106 * Writes the log record
107 *
108 * @param \TYPO3\CMS\Core\Log\LogRecord $record Log record
109 * @return \TYPO3\CMS\Core\Log\Writer\WriterInterface $this
110 * @throws \RuntimeException
111 */
112 public function writeLog(\TYPO3\CMS\Core\Log\LogRecord $record) {
113 if (FALSE === fwrite(self::$logFileHandles[$this->logFile], $record . LF)) {
114 throw new \RuntimeException('Could not write log record to log file', 1345036335);
115 }
116
117 return $this;
118 }
119
120 /**
121 * Opens the log file handle
122 *
123 * @return void
124 * @throws \RuntimeException if the log file can't be opened.
125 */
126 protected function openLogFile() {
127 if (is_resource(self::$logFileHandles[$this->logFile])) {
128 return;
129 }
130
131 $this->createLogFile();
132 self::$logFileHandles[$this->logFile] = fopen($this->logFile, 'a');
133 if (!is_resource(self::$logFileHandles[$this->logFile])) {
134 throw new \RuntimeException('Could not open log file "' . $this->logFile . '"', 1321804422);
135 }
136 }
137
138 /**
139 * Closes the log file handle.
140 *
141 * @return void
142 */
143 protected function closeLogFile() {
144 if (is_resource(self::$logFileHandles[$this->logFile])) {
145 fclose(self::$logFileHandles[$this->logFile]);
146 unset(self::$logFileHandles[$this->logFile]);
147 }
148 }
149
150 /**
151 * Creates the log file with correct permissions
152 * and parent directories, if needed
153 *
154 * @return void
155 */
156 protected function createLogFile() {
157 if (file_exists($this->logFile)) {
158 return;
159 }
160 $logFileDirectory = dirname($this->logFile);
161 if (!@is_dir($logFileDirectory)) {
162 GeneralUtility::mkdir_deep($logFileDirectory);
163 // only create .htaccess, if we created the directory on our own
164 $this->createHtaccessFile($logFileDirectory . '/.htaccess');
165 }
166 // create the log file
167 GeneralUtility::writeFile($this->logFile, '');
168 }
169
170 /**
171 * Creates .htaccess file inside a new directory to access protect it
172 *
173 * @param string $htaccessFile Path of .htaccess file
174 * @return void
175 */
176 protected function createHtaccessFile($htaccessFile) {
177 // write .htaccess file to protect the log file
178 if (!empty($GLOBALS['TYPO3_CONF_VARS']['SYS']['generateApacheHtaccess']) && !file_exists($htaccessFile)) {
179 GeneralUtility::writeFile($htaccessFile, 'Deny From All');
180 }
181 }
182
183 }