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

LaravelLogViewer::directoryTreeStructure()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 38

Duplication

Lines 0
Ratio 0 %

Importance

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