Test Failed
Push — dev ( 9afba2...a28fc9 )
by 世昌
02:21
created

FileLoggerBase::moveFile()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 3
eloc 6
c 1
b 0
f 0
nc 2
nop 1
dl 0
loc 8
rs 10
1
<?php
2
3
4
namespace suda\framework\debug\log\logger;
5
6
use RecursiveDirectoryIterator;
7
use RecursiveIteratorIterator;
8
use suda\framework\debug\ConfigInterface;
9
use suda\framework\debug\ConfigTrait;
10
use suda\framework\debug\log\AbstractLogger;
11
use suda\framework\debug\log\logger\exception\FileLoggerException;
12
use ZipArchive;
13
14
abstract class FileLoggerBase extends AbstractLogger implements ConfigInterface
15
{
16
    use ConfigTrait;
17
18
    /**
19
     * 文件
20
     *
21
     * @var resource
22
     */
23
    protected $temp;
24
    /**
25
     * 临时文件名
26
     *
27
     * @var string
28
     */
29
    protected $tempName;
30
    /**
31
     * 移除文件
32
     *
33
     * @var array
34
     */
35
    protected $removeFiles = [];
36
    /**
37
     * 最后的日志
38
     *
39
     * @var string
40
     */
41
    protected $latest;
42
43
    /**
44
     * @return resource
45
     * @throws FileLoggerException
46
     */
47
    public function getAvailableWrite()
48
    {
49
        if (is_resource($this->temp)) {
50
            return $this->temp;
51
        }
52
        $this->prepareWrite();
53
        return $this->temp;
54
    }
55
56
    /**
57
     * 检查日志文件大小
58
     *
59
     * @return boolean
60
     */
61
    protected function checkSize(): bool
62
    {
63
        $logFile = $this->latest;
64
        if (file_exists($logFile)) {
65
            if (filesize($logFile) > $this->getConfig('max-file-size')) {
66
                return true;
67
            }
68
        }
69
        return false;
70
    }
71
72
    /**
73
     * 删除已经压缩的文件
74
     */
75
    protected function removePackFiles()
76
    {
77
        foreach ($this->removeFiles as $file) {
78
            if (is_file($file) && file_exists($file)) {
79
                unlink($file);
80
            }
81
        }
82
        $this->removeFiles = [];
83
    }
84
85
    /**
86
     * @param string $from
87
     * @param string $to
88
     */
89
    protected function safeMoveKeep(string $from, string $to)
90
    {
91
        $fromFile = fopen($from, 'r');
92
        $toFile = fopen($to, 'w+');
93
        if ($fromFile !== false && $toFile !== false) {
94
            flock($toFile, LOCK_EX);
95
            // 复制内容
96
            stream_copy_to_stream($fromFile, $toFile);
97
            flock($toFile, LOCK_UN);
98
            fclose($toFile);
99
            fclose($fromFile);
100
        }
101
        // 清空内容
102
        $this->clearContent($from);
103
    }
104
105
    /**
106
     * @throws FileLoggerException
107
     */
108
    protected function prepareWrite()
109
    {
110
        $unique = substr(md5(uniqid()), 0, 8);
111
        $save = $this->getConfig('save-path');
112
        $this->tempName = $save . '/' . date('YmdHis') . '.' . $unique . '.log';
113
        $temp = fopen($this->tempName, 'w+');
114
        if ($temp !== false) {
115
            $this->temp = $temp;
116
        } else {
117
            throw new FileLoggerException(__METHOD__ . ':' . sprintf('cannot create log file'));
118
        }
119
        $this->latest = $save . '/' . $this->getConfig('file-name');
120
    }
121
122
    /**
123
     * 获取压缩
124
     *
125
     * @param string $path
126
     * @return ZipArchive|null
127
     */
128
    protected function getZipArchive(string $path)
129
    {
130
        if (class_exists('ZipArchive')) {
131
            $zip = new ZipArchive;
132
            $res = $zip->open($path, ZipArchive::CREATE);
133
            if ($res === true) {
134
                return $zip;
135
            }
136
        }
137
        return null;
138
    }
139
140
    /**
141
     * @param ZipArchive $zip
142
     * @param string $logFile
143
     */
144
    protected function zipFile(ZipArchive $zip, string $logFile)
145
    {
146
        $add = $zip->addFile($logFile, date('Y-m-d') . '-' . $zip->numFiles . '.log');
147
        if (is_dir($this->getConfig('save-dump-path'))) {
148
            $it = new RecursiveIteratorIterator(new RecursiveDirectoryIterator(
149
                $this->getConfig('save-dump-path'),
150
                RecursiveDirectoryIterator::SKIP_DOTS
151
            ));
152
            foreach ($it as $dumpLog) {
153
                if ($zip->addFile($dumpLog, 'dump/' . basename($dumpLog))) {
154
                    array_push($this->removeFiles, $dumpLog);
155
                }
156
            }
157
        }
158
        $zip->close();
159
        if ($add) {
160
            $this->clearContent($logFile);
161
        }
162
    }
163
164
    /**
165
     * @param string $logFile
166
     */
167
    protected function moveFile(string $logFile)
168
    {
169
        if (is_file($logFile) && file_exists($logFile)) {
170
            $this->safeMoveKeep(
171
                $logFile,
172
                $this->getConfig('save-path')
173
                . '/' . date('Y-m-d')
174
                . '-' . substr(md5(uniqid()), 0, 8) . '.log'
175
            );
176
        }
177
    }
178
179
    /**
180
     * 清空内容
181
     * @param string $path
182
     * @return bool
183
     */
184
    protected function clearContent(string $path)
185
    {
186
        $file = fopen($path, 'w');
187
        if ($file !== false) {
188
            fclose($file);
189
            return true;
190
        }
191
        return false;
192
    }
193
194
    /**
195
     * 打包文件
196
     */
197
    protected function packLogFile()
198
    {
199
        $logFile = $this->latest;
200
        $path = preg_replace(
201
            '/[\\\\]+/',
202
            '/',
203
            $this->getConfig('save-zip-path') . '/' . date('Y-m-d') . '.zip'
204
        );
205
        $zip = $this->getZipArchive($path);
206
        if ($zip !== null) {
207
            $this->zipFile($zip, $logFile);
208
        } else {
209
            $this->moveFile($logFile);
210
        }
211
    }
212
213
    /**
214
     * 将临时文件写入最后日志
215
     */
216
    protected function rollLatest()
217
    {
218
        if (isset($this->latest)) {
219
            $latest = fopen($this->latest, 'a+');
220
            if ($latest !== false && flock($latest, LOCK_EX)) {
221
                rewind($this->temp);
222
                stream_copy_to_stream($this->temp, $latest);
223
                flock($latest, LOCK_UN);
224
                if (file_exists($this->tempName)) {
225
                    unlink($this->tempName);
226
                }
227
                fclose($latest);
228
            }
229
            fclose($this->temp);
230
            $this->temp = null;
231
            $this->tempName = null;
232
        }
233
    }
234
}
235