Passed
Push — master ( 01984b...00f43d )
by Malte
03:00
created

Attachment::getExtension()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 1
nc 1
nop 0
dl 0
loc 2
rs 10
c 0
b 0
f 0
1
<?php
2
/*
3
* File:     Attachment.php
4
* Category: -
5
* Author:   M. Goldenbaum
6
* Created:  16.03.18 19:37
7
* Updated:  -
8
*
9
* Description:
10
*  -
11
*/
12
13
namespace Webklex\IMAP;
14
15
use Illuminate\Support\Facades\File;
16
use Symfony\Component\HttpFoundation\File\MimeType\ExtensionGuesser;
17
18
/**
19
 * Class Attachment
20
 *
21
 * @package Webklex\IMAP
22
 */
23
class Attachment {
24
25
    /** @var Message $oMessage */
26
    protected $oMessage;
27
28
    /** @var array $config */
29
    protected $config = [];
30
31
    /** @var object $structure */
32
    protected $structure;
33
34
    /** @var int $part_number */
35
    protected $part_number = 1;
36
37
    /** @var null|string $content */
38
    public $content = null;
39
40
    /** @var null|string $type */
41
    public $type = null;
42
43
    /** @var null|string $content_type */
44
    public $content_type = null;
45
46
    /** @var null|string $id */
47
    public $id = null;
48
49
    /** @var null|string $name */
50
    public $name = null;
51
52
    /** @var null|string $disposition */
53
    public $disposition = null;
54
55
    /** @var null|string $img_src */
56
    public $img_src = null;
57
58
    /**
59
     * Attachment const
60
     *
61
     * @const integer   TYPE_TEXT
62
     * @const integer   TYPE_MULTIPART
63
     * @const integer   TYPE_MESSAGE
64
     * @const integer   TYPE_APPLICATION
65
     * @const integer   TYPE_AUDIO
66
     * @const integer   TYPE_IMAGE
67
     * @const integer   TYPE_VIDEO
68
     * @const integer   TYPE_MODEL
69
     * @const integer   TYPE_OTHER
70
     */
71
    const TYPE_TEXT = 0;
72
    const TYPE_MULTIPART = 1;
73
    const TYPE_MESSAGE = 2;
74
    const TYPE_APPLICATION = 3;
75
    const TYPE_AUDIO = 4;
76
    const TYPE_IMAGE = 5;
77
    const TYPE_VIDEO = 6;
78
    const TYPE_MODEL = 7;
79
    const TYPE_OTHER = 8;
80
81
    /**
82
     * Attachment constructor.
83
     *
84
     * @param Message   $oMessage
85
     * @param object    $structure
86
     * @param integer   $part_number
87
     *
88
     * @throws Exceptions\ConnectionFailedException
89
     */
90
    public function __construct(Message $oMessage, $structure, $part_number = 1) {
91
        $this->config = config('imap.options');
92
93
        $this->oMessage = $oMessage;
94
        $this->structure = $structure;
95
        $this->part_number = ($part_number) ? $part_number : $this->part_number;
96
97
        $this->findType();
98
        $this->fetch();
99
    }
100
101
    /**
102
     * Determine the structure type
103
     */
104
    protected function findType() {
105
        switch ($this->structure->type) {
106
            case self::TYPE_MESSAGE:
107
                $this->type = 'message';
108
                break;
109
            case self::TYPE_APPLICATION:
110
                $this->type = 'application';
111
                break;
112
            case self::TYPE_AUDIO:
113
                $this->type = 'audio';
114
                break;
115
            case self::TYPE_IMAGE:
116
                $this->type = 'image';
117
                break;
118
            case self::TYPE_VIDEO:
119
                $this->type = 'video';
120
                break;
121
            case self::TYPE_MODEL:
122
                $this->type = 'model';
123
                break;
124
            case self::TYPE_TEXT:
125
                $this->type = 'text';
126
                break;
127
            case self::TYPE_MULTIPART:
128
                $this->type = 'multipart';
129
                break;
130
            default:
131
                $this->type = 'other';
132
                break;
133
        }
134
    }
135
136
    /**
137
     * Fetch the given attachment
138
     *
139
     * @throws Exceptions\ConnectionFailedException
140
     */
141
    protected function fetch() {
142
143
        $content = imap_fetchbody($this->oMessage->getClient()->getConnection(), $this->oMessage->getUid(), $this->part_number, $this->oMessage->getFetchOptions() | FT_UID);
0 ignored issues
show
Bug introduced by
It seems like $this->oMessage->getClient()->getConnection() can also be of type true; however, parameter $imap_stream of imap_fetchbody() does only seem to accept resource, maybe add an additional type check? ( Ignorable by Annotation )

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

143
        $content = imap_fetchbody(/** @scrutinizer ignore-type */ $this->oMessage->getClient()->getConnection(), $this->oMessage->getUid(), $this->part_number, $this->oMessage->getFetchOptions() | FT_UID);
Loading history...
144
145
        $this->content_type = $this->type.'/'.strtolower($this->structure->subtype);
146
        $this->content = $this->oMessage->decodeString($content, $this->structure->encoding);
147
148
        if (property_exists($this->structure, 'id')) {
149
            $this->id = str_replace(['<', '>'], '', $this->structure->id);
150
        }
151
152
        if (property_exists($this->structure, 'dparameters')) {
153
            foreach ($this->structure->dparameters as $parameter) {
154
                if (strtolower($parameter->attribute) == "filename") {
155
                    $this->setName($parameter->value);
156
                    $this->disposition = property_exists($this->structure, 'disposition') ? $this->structure->disposition : null;
157
                    break;
158
                }
159
            }
160
        }
161
162
        if (self::TYPE_MESSAGE == $this->structure->type) {
163
            if ($this->structure->ifdescription) {
164
                $this->setName($this->structure->description);
165
            } else {
166
                $this->setName($this->structure->subtype);
167
            }
168
        }
169
170
        if (!$this->name && property_exists($this->structure, 'parameters')) {
171
            foreach ($this->structure->parameters as $parameter) {
172
                if (strtolower($parameter->attribute) == "name") {
173
                    $this->setName($parameter->value);
174
                    $this->disposition = property_exists($this->structure, 'disposition') ? $this->structure->disposition : null;
175
                    break;
176
                }
177
            }
178
        }
179
    }
180
181
    /**
182
     * Save the attachment content to your filesystem
183
     *
184
     * @param string|null $path
185
     * @param string|null $filename
186
     *
187
     * @return boolean
188
     */
189
    public function save($path = null, $filename = null) {
190
        $path = $path ?: storage_path();
191
        $filename = $filename ?: $this->getName();
192
193
        $path = substr($path, -1) == DIRECTORY_SEPARATOR ? $path : $path.DIRECTORY_SEPARATOR;
194
195
        return File::put($path.$filename, $this->getContent()) !== false;
196
    }
197
198
    /**
199
     * @return null|string
200
     */
201
    public function getContent() {
202
        return $this->content;
203
    }
204
205
    /**
206
     * @return null|string
207
     */
208
    public function getType() {
209
        return $this->type;
210
    }
211
212
    /**
213
     * @return null|string
214
     */
215
    public function getContentType() {
216
        return $this->content_type;
217
    }
218
219
    /**
220
     * @return null|string
221
     */
222
    public function getId() {
223
        return $this->id;
224
    }
225
226
    /**
227
     * @param $name
228
     */
229
    public function setName($name) {
230
        if($this->config['decoder']['message']['subject'] === 'utf-8') {
231
            $this->name = imap_utf8($name);
232
        }else{
233
            $this->name = mb_decode_mimeheader($name);
234
        }
235
    }
236
237
    /**
238
     * @return null|string
239
     */
240
    public function getName() {
241
        return $this->name;
242
    }
243
244
    /**
245
     * @return null|string
246
     */
247
    public function getDisposition() {
248
        return $this->disposition;
249
    }
250
251
    /**
252
     * @return null|string
253
     */
254
    public function getImgSrc() {
255
        if ($this->type == 'image' && $this->img_src == null) {
0 ignored issues
show
Bug introduced by
It seems like you are loosely comparing $this->img_src of type null|string against null; this is ambiguous if the string can be empty. Consider using a strict comparison === instead.
Loading history...
256
            $this->img_src = 'data:'.$this->content_type.';base64,'.base64_encode($this->content);
257
        }
258
        return $this->img_src;
259
    }
260
261
    /**
262
     * @return string|null
263
     */
264
    public function getMimeType(){
265
        return (new \finfo())->buffer($this->getContent(), FILEINFO_MIME_TYPE);
266
    }
267
268
    /**
269
     * @return string|null
270
     */
271
    public function getExtension(){
272
        return ExtensionGuesser::getInstance()->guess($this->getMimeType());
273
    }
274
}