Test Setup Failed
Push — main ( 53f204...e8010f )
by ikechukwu
04:09
created

ClamAV::scanstream()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 20
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 4
eloc 12
c 1
b 0
f 0
nc 4
nop 1
dl 0
loc 20
rs 9.8666
1
<?php
2
3
namespace Ikechukwukalu\Clamavfileupload\Trait;
4
5
/*
6
 * ClamAV.php
7
 *
8
 * A simple PHP class for scanning files using ClamAV.
9
 *
10
 * Copyright (C) 2017 KISS IT Consulting <http://www.kissitconsulting.com/>
11
 * Redistribution and use in source and binary forms, with or without
12
 * modification, are permitted provided that the following conditions
13
 * are met:
14
 *
15
 * 1. Redistributions of source code must retain the above copyright
16
 *    notice, this list of conditions and the following disclaimer.
17
 * 2. Redistributions in binary form must reproduce the above
18
 *    copyright notice, this list of conditions and the following
19
 *    disclaimer in the documentation and/or other materials
20
 *    provided with the distribution.
21
 *
22
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
25
 * A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL ANY
26
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
27
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
28
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
29
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
30
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
31
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
32
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33
*/
34
35
/**
36
 * 1. Go to <https://github.com/kissit/php-clamav-scan> to view the original
37
 *    PHP file.
38
 * 2. Go to <https://github.com/ikechukwukalu> to view my personal
39
 *    GitHub account.
40
*/
41
42
trait ClamAV {
43
44
    private static $message;
45
46
    /**
47
     * Private function to open a socket
48
     * to clamd based on the current options.
49
     */
50
    private static function socket()
51
    {
52
        if(empty(config('clamavfileupload.clamd_ip')) && empty(config('clamavfileupload.clamd_ip'))) {
53
            // By default we just use the local socket
54
            $socket = socket_create(AF_UNIX, SOCK_STREAM, 0);
55
56
            if(socket_connect($socket, config('clamavfileupload.clamd_sock'))) {
57
                self::$message = trans('clamavfileupload::clamav.socket_connected');
58
                return $socket;
59
            }
60
        }
61
62
        // Attempt to use a network based socket
63
        $socket = socket_create(AF_INET, SOCK_STREAM, 0);
64
65
        if(socket_connect($socket, config('clamavfileupload.clamd_ip'), config('clamavfileupload.clamd_ip'))) {
66
            self::$message = trans('clamavfileupload::clamav.socket_connected');
67
            return $socket;
68
        }
69
70
        self::$message = trans('clamavfileupload::clamav.unable_to_open_socket');
71
        return false;
72
    }
73
74
    /**
75
     * Get the last scan message.
76
     *
77
     * @return string
78
     */
79
    public static function getMessage(): string
80
    {
81
        return self::$message;
82
    }
83
84
    /**
85
     * Function to ping Clamd to make sure its functioning.
86
     *
87
     * @return bool
88
     */
89
    public static function ping(): bool
90
    {
91
        $ping = self::send("PING");
92
93
        if($ping == "PONG") {
94
            return true;
95
        }
96
97
        self::$message = trans('clamavfileupload::clamav.not_running');
98
        return false;
99
    }
100
101
    /**
102
     * Function to scan the passed in file.
103
     * Returns true if safe, false otherwise.
104
     *
105
     * @return bool
106
     */
107
    public static function scan($file): bool
108
    {
109
        if(!file_exists($file)) {
110
            self::$message = trans('clamavfileupload::clamav.file_not_found',
111
                ['name' => $file]);
112
            return false;
113
        }
114
115
        $scan = self::send("SCAN $file");
116
        if($scan === false) {
117
            self::$message = trans('clamavfileupload::clamav.not_running');
118
            return false;
119
        }
120
121
        $scanMessage = trim(substr(strrchr($scan, ":"), 1));
0 ignored issues
show
Bug introduced by
$scan of type true is incompatible with the type string expected by parameter $haystack of strrchr(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

121
        $scanMessage = trim(substr(strrchr(/** @scrutinizer ignore-type */ $scan, ":"), 1));
Loading history...
122
        if($scanMessage == 'OK') {
123
            self::$message = $scanMessage;
124
            return true;
125
        }
126
127
        self::$message = trans('clamavfileupload::clamav.file_not_safe',
128
            ['name' => $file]);
129
        return false;
130
    }
131
132
    /**
133
     * Function to scan the passed in stream.
134
     * Returns true if safe, false otherwise.
135
     *
136
     * @param any $file
0 ignored issues
show
Bug introduced by
The type Ikechukwukalu\Clamavfileupload\Trait\any was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
137
     * @return bool
138
     */
139
    public static function scanstream($file): bool
140
    {
141
        $socket = self::socket();
142
        if(!$socket) {
143
            self::$message = trans('clamavfileupload::clamav.not_running');
144
            return false;
145
        }
146
147
        if(!file_exists($file)) {
148
            self::$message = trans('clamavfileupload::clamav.file_not_found');
149
            return false;
150
        }
151
152
        if ($scan_fh = fopen($file, 'rb')) {
153
            return self::scanStreamSend($scan_fh, $socket, $file);
154
        }
155
156
        self::$message = trans('clamavfileupload::clamav.file_not_safe',
157
            ['name' => $file]);
158
        return false;
159
    }
160
161
    private static function scanStreamSend($scan_fh, $socket, $file) {
162
        $chunksize = filesize($file) < 8192 ? filesize($file) : 8192;
163
        $command = "zINSTREAM\0";
164
        socket_send($socket, $command, strlen($command), 0);
165
166
        while (!feof($scan_fh)) {
167
            $data = fread($scan_fh, $chunksize);
168
            $packet = pack(sprintf("Na%d", strlen($data)), strlen($data), $data);
169
            socket_send($socket, $packet, strlen($packet), 0);
170
        }
171
172
        $packet = pack("Nx",0);
173
        socket_send($socket, $packet, strlen($packet), 0);
174
        socket_recv($socket, $scan, config('clamavfileupload.clamd_sock_len'), 0);
175
        socket_close($socket);
176
177
        if($scan === false) {
178
            self::$message = trans('clamavfileupload::clamav.not_running');
179
            return false;
180
        }
181
182
        $scanMessage = trim(substr(strrchr($scan, ":"), 1));
183
        if($scanMessage == 'OK') {
184
            self::$message = $scanMessage;
185
            return true;
186
        }
187
188
        self::$message = trans('clamavfileupload::clamav.file_not_safe',
189
            ['name' => $file]);
190
        return false;
191
    }
192
193
    /**
194
     * Function to send a command to the Clamd socket.
195
     * In case you need to send any other commands directly.
196
     *
197
     * @return bool
198
     */
199
    public static function send($command) {
200
        if(empty($command)) {
201
            return false;
202
        }
203
204
        try {
205
            $socket = self::socket();
206
207
            if($socket) {
208
                socket_send($socket, $command, strlen($command), 0);
209
                socket_recv($socket, $return, config('clamavfileupload.clamd_sock_len'), 0);
210
                socket_close($socket);
211
212
                return trim($return);
0 ignored issues
show
Bug Best Practice introduced by
The expression return trim($return) returns the type string which is incompatible with the documented return type boolean.
Loading history...
213
            }
214
        } catch (\ErrorException $e) {
215
            self::$message = $e->getMessage();
216
        }
217
218
        return false;
219
    }
220
}
221