Completed
Pull Request — master (#209)
by Zacchaeus
01:13
created

LaravelLogViewer::setFile()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 9
rs 9.9666
c 0
b 0
f 0
cc 2
nc 2
nop 1
1
<?php
2
3
namespace Rap2hpoutre\LaravelLogViewer;
4
5
/**
6
 * Class LaravelLogViewer
7
 * @package Rap2hpoutre\LaravelLogViewer
8
 */
9
class LaravelLogViewer
10
{
11
    /**
12
     * @var string file
13
     */
14
    private $file;
15
16
    /**
17
     * @var string folder
18
     */
19
    private $folder;
20
21
    /**
22
     * @var string storage_path
23
     */
24
    private $storage_path;
25
26
    /**
27
     * Why? Uh... Sorry
28
     */
29
    const MAX_FILE_SIZE = 52428800;
30
31
    /**
32
     * @var Level level
33
     */
34
    private $level;
35
36
    /**
37
     * @var Pattern pattern
38
     */
39
    private $pattern;
40
41
    /**
42
     * LaravelLogViewer constructor.
43
     */
44
    public function __construct()
45
    {
46
        $this->level = new Level();
47
        $this->pattern = new Pattern();
48
        $this->storage_path = function_exists('config') ? config('logviewer.storage_path', storage_path('logs')) : storage_path('logs');
49
50
    }
51
52
    /**
53
     * @param string $folder
54
     */
55
    public function setFolder($folder)
56
    {
57
        if (app('files')->exists($folder)) {
58
            $this->folder = $folder;
59
        }
60
        if(is_array($this->storage_path)) {
61 View Code Duplication
            foreach ($this->storage_path as $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
62
                $logsPath = $value . '/' . $folder;
63
                if (app('files')->exists($logsPath)) {
64
                    $this->folder = $folder;
65
                    break;
66
                }
67
            }
68
        } else {
69
            if ($this->storage_path) {
70
                $logsPath = $this->storage_path . '/' . $folder;
71
                if (app('files')->exists($logsPath)) {
72
                    $this->folder = $folder;
73
                }
74
            }
75
        }
76
    }
77
78
    /**
79
     * @param string $file
80
     * @throws \Exception
81
     */
82
    public function setFile($file)
83
    {
84
85
        $file = $this->pathToLogFile($file);
86
87
        if (app('files')->exists($file)) {
88
            $this->file = $file;
89
        }
90
    }
91
92
    /**
93
     * @param string $file
94
     * @return string
95
     * @throws \Exception
96
     */
97
    public function pathToLogFile($file)
98
    {
99
100
        if (app('files')->exists($file)) { // try the absolute path
101
            return $file;
102
        }
103
        if (is_array($this->storage_path)) {
104 View Code Duplication
            foreach ($this->storage_path as $folder) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
105
                if (app('files')->exists($folder . '/' . $file)) { // try the absolute path
106
                    $file = $folder . '/' . $file;
107
                    break;
108
                }
109
            }
110
            return $file;
111
        }
112
113
        $logsPath = $this->storage_path;
114
        $logsPath .= ($this->folder) ? '/' . $this->folder : '';
115
        $file = $logsPath . '/' . $file;
116
        // check if requested file is really in the logs directory
117
        if (dirname($file) !== $logsPath) {
118
            throw new \Exception('No such log file: '.$file);
119
        }
120
        return $file;
121
    }
122
123
    /**
124
     * @return string
125
     */
126
    public function getFolderName()
127
    {
128
        return $this->folder;
129
    }
130
131
    /**
132
     * @return string
133
     */
134
    public function getFileName()
135
    {
136
        return basename($this->file);
137
    }
138
139
    /**
140
     * @return array
141
     */
142
    public function all()
143
    {
144
        $log = array();
145
146
        if (!$this->file) {
147
            $log_file = (!$this->folder) ? $this->getFiles() : $this->getFolderFiles();
148
            if (!count($log_file)) {
149
                return [];
150
            }
151
            $this->file = $log_file[0];
152
        }
153
154
        $max_file_size = function_exists('config') ? config('logviewer.max_file_size', self::MAX_FILE_SIZE) : self::MAX_FILE_SIZE;
155
        if (app('files')->size($this->file) > $max_file_size) {
156
            return null;
157
        }
158
159
        $file = app('files')->get($this->file);
160
161
        preg_match_all($this->pattern->getPattern('logs'), $file, $headings);
162
163
        if (!is_array($headings)) {
164
            return $log;
165
        }
166
167
        $log_data = preg_split($this->pattern->getPattern('logs'), $file);
168
169
        if ($log_data[0] < 1) {
170
            array_shift($log_data);
171
        }
172
173
        foreach ($headings as $h) {
174
            for ($i = 0, $j = count($h); $i < $j; $i++) {
175
                foreach ($this->level->all() as $level) {
176
                    if (strpos(strtolower($h[$i]), '.' . $level) || strpos(strtolower($h[$i]), $level . ':')) {
177
178
                        preg_match($this->pattern->getPattern('current_log', 0) . $level . $this->pattern->getPattern('current_log', 1), $h[$i], $current);
179
                        if (!isset($current[4])) {
180
                            continue;
181
                        }
182
183
                        $log[] = array(
184
                            'context' => $current[3],
185
                            'level' => $level,
186
                            'folder' => $this->folder,
187
                            'level_class' => $this->level->cssClass($level),
188
                            'level_img' => $this->level->img($level),
189
                            'date' => $current[1],
190
                            'text' => $current[4],
191
                            'in_file' => isset($current[5]) ? $current[5] : null,
192
                            'stack' => preg_replace("/^\n*/", '', $log_data[$i])
193
                        );
194
                    }
195
                }
196
            }
197
        }
198
199
        if (empty($log)) {
200
201
            $lines = explode(PHP_EOL, $file);
202
            $log = [];
203
204
            foreach ($lines as $key => $line) {
205
                $log[] = [
206
                    'context' => '',
207
                    'level' => '',
208
                    'folder' => '',
209
                    'level_class' => '',
210
                    'level_img' => '',
211
                    'date' => $key + 1,
212
                    'text' => $line,
213
                    'in_file' => null,
214
                    'stack' => '',
215
                ];
216
            }
217
        }
218
219
        return array_reverse($log);
220
    }
221
222
    /**Creates a multidimensional array
223
     * of subdirectories and files
224
     * @return array
225
     */
226
    public function foldersAndFiles($path = null)
227
    {
228
	    $contents = array();
229
	    $dir = $path ?? $this->storage_path;
230
	    foreach (scandir($dir) as $node) {
231
		    if ($node == '.' || $node == '..') continue;
232
		    $path = $dir . '\\' . $node;
233
		    if (is_dir($path)) {
234
			    $contents[$path] = $this->foldersAndFiles($path);
235
		    } else {
236
			    $contents[] = $path;
237
		    }
238
	    }
239
240
	    return $contents;
241
    }
242
243
	/**Returns an array of
244
	 * all subdirectories of specified directory
245
	 *
246
	 * @param string $folder
247
	 *
248
	 * @return array
249
	 */
250
    public function getFolders($folder = '')
251
    {
252
	    $folders = [];
253
	    $listObject = new \RecursiveIteratorIterator(
254
		    new \RecursiveDirectoryIterator($this->storage_path.'/'.$folder, \RecursiveDirectoryIterator::SKIP_DOTS),
255
		    \RecursiveIteratorIterator::CHILD_FIRST
256
	    );
257
	    foreach ($listObject as $fileinfo) {
258
		    if($fileinfo->isDir()) $folders[] = $fileinfo->getRealPath();
259
	    }
260
	    return $folders;
261
    }
262
263
    /**
264
     * @param bool $basename
265
     * @return array
266
     */
267
    public function getFolderFiles($basename = false)
268
    {
269
        return $this->getFiles($basename, $this->folder);
270
    }
271
272
    /**
273
     * @param bool $basename
274
     * @param string $folder
275
     * @return array
276
     */
277
    public function getFiles($basename = false, $folder = '')
278
    {
279
	    $files = [];
280
	    $pattern = function_exists('config') ? config('logviewer.pattern', '*.log') : '*.log';
281
	    $fullPath = $this->storage_path.'/'.$folder;
282
283
	    $listObject = new \RecursiveIteratorIterator(
284
		    new \RecursiveDirectoryIterator($fullPath, \RecursiveDirectoryIterator::SKIP_DOTS),
285
		    \RecursiveIteratorIterator::CHILD_FIRST
286
	    );
287
288
	    foreach ($listObject as $fileinfo) {
289
		    if(!$fileinfo->isDir() && strtolower(pathinfo($fileinfo->getRealPath(), PATHINFO_EXTENSION)) == explode('.', $pattern)[1])
290
			    $files[] = $basename ? basename($fileinfo->getRealPath()) : $fileinfo->getRealPath();
291
	    }
292
	    return $files;
293
    }
294
295
	/**
296
	 * @return \Illuminate\Config\Repository|mixed|string
297
	 */
298
    public function getStoragePath()
299
    {
300
    	return $this->storage_path;
301
    }
302
303
	/**
304
	 * @param $path
305
	 *
306
	 * @return \Illuminate\Config\Repository|mixed|string
307
	 */
308
	public function setStoragePath($path)
309
	{
310
		$this->storage_path = $path;
311
	}
312
313
    public static function directoryTreeStructure($storage_path, array $array) : void {
314
	    foreach ($array as $k => $v) {
315
		    if(is_dir( $k )) {
316
317
			    $exploded = explode( "\\", $k );
318
			    $show = last( $exploded );
319
320
			    echo '<div class="list-group folder">
321
				    <a href="?f='. \Illuminate\Support\Facades\Crypt::encrypt($k).'">
322
					    <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span
323
						    class="fa fa-folder"></span> '.$show.'
324
				    </a>
325
			    </div>';
326
327
			    if ( is_array( $v ) ) {
328
				    self::directoryTreeStructure( $storage_path, $v );
329
			    }
330
331
		    }
332
		    else {
333
334
			    $exploded = explode( "\\", $v );
335
			    $show2 = last( $exploded );
336
			    $folder = str_replace( $storage_path, "", rtrim( str_replace( $show2, "", $v ), "\\" ) );
337
			    $file = $v;
338
339
340
			   echo '<div class="list-group">
341
				    <a href="?l='.\Illuminate\Support\Facades\Crypt::encrypt($file).'&f='.\Illuminate\Support\Facades\Crypt::encrypt($folder).'">
342
					    <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span> <span
343
						    class="fa fa-file"></span> '.$show2.'
344
				    </a>
345
			    </div>';
346
347
		    }
348
	    }
349
    }
350
}
351