Issues (77)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Header Injection
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

src/Model/Entity/ContentsFileTrait.php (13 issues)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace ContentsFile\Model\Entity;
4
5
use Cake\Core\Configure;
6
use Cake\Filesystem\File;
7
use Cake\Http\Exception\InternalErrorException;
8
use Cake\I18n\Time;
9
use Cake\ORM\TableRegistry;
10
use Cake\Utility\Security;
11
use ContentsFile\Aws\S3;
12
use Laminas\Diactoros\UploadedFile;
13
14
trait ContentsFileTrait
15
{
16
    private $contentsFileSettings = [];
17
18
    /**
19
     * contentsFileSettings
20
     * 設定値のセッティング
21
     *
22
     * @author hagiwara
23
     * @return void
24
     */
25
    private function contentsFileSettings(): void
26
    {
27
        $default = [];
28
        //設定値はまとめる
29
        $settings = $this->contentsFileConfig;
0 ignored issues
show
The property contentsFileConfig does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
30
        $this->contentsFileSettings = array_merge($default, $settings);
31
    }
32
33
    /**
34
     * getContentsFileSettings
35
     * 設定値のセッティングの取得
36
     *
37
     * @author hagiwara
38
     * @return array
39
     */
40
    public function getContentsFileSettings(): array
41
    {
42
        if (empty($this->contentsFileSettings)) {
43
            $this->contentsFileSettings();
44
        }
45
        return $this->contentsFileSettings;
46
    }
47
48
    /**
49
     * getContentsFile
50
     * ファイルのgetterのセッティング
51
     *
52
     * @author hagiwara
53
     * @param string $property
54
     * @param mixed $value
55
     * @return mixed
56
     */
57
    public function getContentsFile(string $property, $value)
58
    {
59
        $this->contentsFileSettings();
60
        if (
61
            //attachmentにデータが登録時のみ
62
            !empty($this->id) &&
63
            //設定値に設定されているとき
64
            preg_match('/^contents_file_(.*)$/', $property, $match) &&
65
            array_key_exists($match[1], $this->contentsFileSettings['fields'])
66
        ) {
67
            //何もセットされていないとき
68
            if (empty($this->_fields[$property])) {
69
                //attachmentからデータを探しに行く
70
                $attachmentModel = TableRegistry::getTableLocator()->get('Attachments');
71
                $attachmentData = $attachmentModel->find('all')
72
                    ->where(['model' => $this->getSource()])
0 ignored issues
show
It seems like getSource() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
73
                    ->where(['model_id' => $this->id])
0 ignored issues
show
The property id does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
74
                    ->where(['field_name' => $match[1]])
75
                    ->first()
76
                ;
77
                if (!empty($attachmentData)) {
78
                    $value = [
79
                        'model' => $attachmentData->model,
80
                        'model_id' => $attachmentData->model_id,
81
                        'field_name' => $attachmentData->field_name,
82
                        'file_name' => $attachmentData->file_name,
83
                        'file_content_type' => $attachmentData->file_content_type,
84
                        'file_size' => $attachmentData->file_size,
85
                        'file_random_path' => $attachmentData->file_random_path,
86
                    ];
87
                }
88
            } else {
89
                //それ以外はpropertiesの値を取得(setterで値を編集している場合はそれを反映するために必要)
90
                $value = $this->_fields[$property];
0 ignored issues
show
The property _fields does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
91
            }
92
        }
93
        return $value;
94
    }
95
96
    /**
97
     * setContentsFile
98
     * ファイルのsetterのセッティング
99
     *
100
     * @author hagiwara
101
     */
102
    public function setContentsFile()
103
    {
104
        $this->contentsFileSettings();
105
        foreach ($this->contentsFileSettings['fields'] as $field => $fieldSetting) {
106
            // 通常のパターン
107
            if (!array_key_exists('type', $fieldSetting) || $fieldSetting['type'] == 'normal') {
108
                $this->normalSetContentsFile($field, $fieldSetting);
109
            } else {
110
                $this->ddSetContentsFile($field, $fieldSetting);
111
            }
112
        }
113
        return $this;
114
    }
115
116
    /**
117
     * normalSetContentsFile
118
     * ファイルのsetterのセッティング
119
     *
120
     * @param string $field
121
     * @param array $fieldSetting
122
     * @return void
123
     * @author hagiwara
124
     */
125
    private function normalSetContentsFile(string $field, array $fieldSetting): void
126
    {
127
        $fileInfo = $this->{$field};
128
        if (
129
            //ファイルの情報がある
130
            is_object($fileInfo) &&
131
            //空アップロード時は通さない(もともとのデータを活かす)
132
            $fileInfo->getError() != UPLOAD_ERR_NO_FILE
133
        ) {
134
            $fileSet = [
135
                'model' => $this->getSource(),
0 ignored issues
show
It seems like getSource() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
136
                'model_id' => $this->id,
137
                'field_name' => $field,
138
                'file_name' => $fileInfo->getClientFilename(),
139
                'file_content_type' => Configure::read('ContentsFile.Setting.type'),
140
                'file_size' => $fileInfo->getSize(),
141
                'file_error' => $fileInfo->getError(),
142
            ];
143
144
            //$fileInfoにtmp_nameがいるときはtmpディレクトリへのファイルのコピーを行う
145
            // if (!empty($fileInfo['tmp_name'])) {
146
            $tmpFileName = Security::hash(rand() . Time::now()->i18nFormat('YYYY/MM/dd HH:ii:ss') . $fileInfo->getClientFilename());
147
148
            if ($this->getExt($fileInfo->getClientFilename()) !== null) {
149
                $tmpFileName .= '.' . $this->getExt($fileInfo->getClientFilename());
150
            }
151
152
            // tmpディレクトリへのアップロードのエラー(パーミッションなど)
153
            if (!$this->tmpUpload($fileInfo, $fieldSetting, $tmpFileName)) {
154
                throw new InternalErrorException('tmp upload error');
155
            }
156
            $fileSet['tmp_file_name'] = $tmpFileName;
157
            // }
158
            //これを残して次に引き渡したくないので
159
            unset($this->{$field});
160
161
            $nowNew = $this->isNew();
0 ignored issues
show
It seems like isNew() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
$nowNew is not used, you could remove the assignment.

This check looks for variable assignements that are either overwritten by other assignments or where the variable is not used subsequently.

$myVar = 'Value';
$higher = false;

if (rand(1, 6) > 3) {
    $higher = true;
} else {
    $higher = false;
}

Both the $myVar assignment in line 1 and the $higher assignment in line 2 are dead. The first because $myVar is never used and the second because $higher is always overwritten for every possible time line.

Loading history...
162
163
            $this->set('contents_file_' . $field, $fileSet);
0 ignored issues
show
It seems like set() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
164
            $this->set('contents_file_' . $field . '_filename', $fileInfo->getClientFilename());
0 ignored issues
show
It seems like set() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
165
        }
166
    }
167
168
    /**
169
     * ddSetContentsFile
170
     * ファイルのsetterのセッティング
171
     *
172
     * @param string $field
173
     * @param array $fieldSetting
174
     * @return void
175
     * @author hagiwara
176
     */
177
    private function ddSetContentsFile(string $field, array $fieldSetting): void
178
    {
179
180
        $fileInfo = $this->{$field};
181
        if (!empty($fileInfo)) {
182
            if (!preg_match('/^data:([^;]+);base64,(.+)$/', $fileInfo, $fileMatch)) {
183
                // ちゃんとファイルアップがないのでエラー
184
                throw new InternalErrorException('tmp upload erroar');
185
            }
186
            $filename = $this->{'contents_file_' . $field . '_filename'};
187
188
            $filebody = base64_decode($fileMatch[2]);
189
            $filesize = strlen($filebody);
190
191
            $tmpFileName = Security::hash(rand() . Time::now()->i18nFormat('YYYY/MM/dd HH:ii:ss') . $filename);
192
193
            if ($this->getExt($filename) !== null) {
194
                $tmpFileName .= '.' . $this->getExt($filename);
195
            }
196
            // まずは一時的にファイルを書き出す
197
            $ddTmpFileName = TMP . Security::hash(rand() . Time::now()->i18nFormat('YYYY/MM/dd HH:ii:ss') . $filename);
198
            $fp = new File($ddTmpFileName);
0 ignored issues
show
Deprecated Code introduced by
The class Cake\Filesystem\File has been deprecated with message: 4.0.0 Will be removed in 5.0.

This class, trait or interface has been deprecated. The supplier of the file has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the type will be removed from the class and what other constant to use instead.

Loading history...
199
            $fp->write($filebody);
200
201
            // tmpディレクトリへのアップロードのエラー(パーミッションなど)
202
            if (!$this->tmpUpload($ddTmpFileName, $fieldSetting, $tmpFileName)) {
0 ignored issues
show
$ddTmpFileName is of type string, but the function expects a object<Laminas\Diactoros\UploadedFile>.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
203
                throw new InternalErrorException('tmp upload error');
204
            }
205
            $fp->delete();
206
            $fp->close();
207
208
            $fileSet = [
209
                'model' => $this->getSource(),
0 ignored issues
show
It seems like getSource() must be provided by classes using this trait. How about adding it as abstract method to this trait?

This check looks for methods that are used by a trait but not required by it.

To illustrate, let’s look at the following code example

trait Idable {
    public function equalIds(Idable $other) {
        return $this->getId() === $other->getId();
    }
}

The trait Idable provides a method equalsId that in turn relies on the method getId(). If this method does not exist on a class mixing in this trait, the method will fail.

Adding the getId() as an abstract method to the trait will make sure it is available.

Loading history...
210
                'model_id' => $this->id,
211
                'field_name' => $field,
212
                'file_name' => $filename,
213
                'file_content_type' => Configure::read('ContentsFile.Setting.type'),
214
                'file_size' => $filesize,
215
                'file_error' => 0,
216
            ];
217
218
            $fileSet['tmp_file_name'] = $tmpFileName;
219
220
            //これを残して次に引き渡したくないので
221
            unset($this->{$field});
222
223
            $this->{'contents_file_' . $field} = $fileSet;
224
            $this->{'contents_file_' . $field . '_filename'} = $filename;
225
        }
226
    }
227
228
    /**
229
     * getExt
230
     * 拡張子の取得
231
     *
232
     * @author hagiwara
233
     * @param string $file
234
     * @return string|null
235
     */
236
    private function getExt(string $file): ?string
237
    {
238
        $fileExplode = explode('.', $file);
239
        //この場合拡張子なし
240
        if (count($fileExplode) == 1) {
241
            return null;
242
        }
243
        return $fileExplode[(count($fileExplode) - 1)];
244
    }
245
246
    /**
247
     * tmpUpload
248
     * tmpディレクトリへのアップロード
249
     *
250
     * @author hagiwara
251
     * @param \Laminas\Diactoros\UploadedFile $fileInfo
252
     * @param array $fieldSetting
253
     * @param string $tmpFileName
254
     * @return mixed
255
     */
256
    private function tmpUpload(UploadedFile $fileInfo, array $fieldSetting, string $tmpFileName)
0 ignored issues
show
The parameter $fieldSetting is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
257
    {
258
        // すでにtraitのため、ここはif文での分岐処理
259
        if (Configure::read('ContentsFile.Setting.type') == 'normal') {
260
            $fileInfo->moveTo(Configure::read('ContentsFile.Setting.Normal.tmpDir') . $tmpFileName);
261
            // 向きの調整をする場合
262
            if (Configure::read('ContentsFile.Setting.exifRotate') == true) {
263
                $this->orientationFixedImage($tmpFileName, $tmpFileName);
264
            }
265
266
            return true;
267
268
        } elseif (Configure::read('ContentsFile.Setting.type') == 's3') {
269
            $tmpName = Configure::read('ContentsFile.Setting.S3.workingDir') . $tmpFileName;
270
            $fileInfo->moveTo($tmpName);
271
            $uploadFileName = Configure::read('ContentsFile.Setting.S3.tmpDir') . $tmpFileName;
272
273
            $S3 = new S3();
274
            return $S3->upload($tmpName, $uploadFileName);
275
        } else {
276
            throw new InternalErrorException('contentsFileConfig type illegal');
277
        }
278
    }
279
280
    /**
281
     * orientationFixedImage
282
     * http://www.glic.co.jp/blog/archives/88 よりコピペ
283
     * 画像の方向を正す
284
     * 向きだけロジックが逆そうなので調整
285
     *
286
     * @param string $input
287
     * @param string $output
288
     * @return void
289
     * @author hagiwara
290
     */
291
    private function orientationFixedImage(string $input, string $output): void
292
    {
293
        $imagetype = exif_imagetype($input);
294
        // 何も取れない場合何もしない
295
        if ($imagetype === false) {
296
            return;
297
        }
298
        // exif情報の取得
299
        $exif_datas = [];
300
        // 画像読み込み
301
        switch ($imagetype) {
302
            case IMAGETYPE_GIF:
303
                $image = ImageCreateFromGIF($input);
304
                break;
305
            case IMAGETYPE_JPEG:
306
                $image = ImageCreateFromJPEG($input);
307
                // exif情報の取得(jpegのみ
308
                $exif_datas = @exif_read_data($input);
309
                break;
310
            case IMAGETYPE_PNG:
311
                $image = ImageCreateFromPNG($input);
312
                break;
313
            default:
314
                $image = false;
315
        }
316
317
        // 画像以外は何もしない
318
        if (!$image) {
319
            return;
320
        }
321
322
        // 向き補正
323
        if(isset($exif_datas['Orientation'])){
324
            $orientation = $exif_datas['Orientation'];
325
            if($image){
326
                // 未定義
327
                if($orientation == 0) {
328
                    // 通常
329
                }else if($orientation == 1) {
330
                    // 左右反転
331
                }else if($orientation == 2) {
332
                    $image = $this->imageFlop($image);
333
                    // 180°回転
334
                }else if($orientation == 3) {
335
                    $image = $this->imageRotate($image,180, 0);
336
                    // 上下反転
337
                }else if($orientation == 4) {
338
                    $image = $this->imageFlip($image);
339
                    // 反時計回りに90°回転 上下反転
340
                }else if($orientation == 5) {
341
                    $image = $this->imageRotate($image,90, 0);
342
                    $image = $this->imageFlip($image);
343
                    // 時計回りに90°回転
344
                }else if($orientation == 6) {
345
                    $image = $this->imageRotate($image,-90, 0);
346
                    // 時計回りに90°回転 上下反転
347
                }else if($orientation == 7) {
348
                    $image = $this->imageRotate($image,-90, 0);
349
                    $image = $this->imageFlip($image);
350
                // 反時計回りに90°回転
351
                }else if($orientation == 8) {
352
                    $image = $this->imageRotate($image,90, 0);
353
                }
354
            }
355
        }
356
357
        switch ($imagetype) {
358
            case IMAGETYPE_GIF:
359
                ImageGIF($image ,$output);
360
                break;
361
            case IMAGETYPE_JPEG:
362
                ImageJPEG($image ,$output, 100);
363
                break;
364
            case IMAGETYPE_PNG:
365
                ImagePNG($image ,$output);
366
                break;
367
            default:
368
                return;
369
        }
370
    }
371
372
    /**
373
     * imageFlop
374
     * http://www.glic.co.jp/blog/archives/88 よりコピペ
375
     * 画像の左右反転
376
     *
377
     * @param resource $image
378
     * @return resource
379
     * @author hagiwara
380
     */
381
    private function imageFlop($image)
382
    {
383
        // 画像の幅を取得
384
        $w = imagesx($image);
385
        // 画像の高さを取得
386
        $h = imagesy($image);
387
        // 変換後の画像の生成(元の画像と同じサイズ)
388
        $destImage = @imagecreatetruecolor($w,$h);
389
        // 逆側から色を取得
390
        for($i=($w-1);$i>=0;$i--){
391
            for($j=0;$j<$h;$j++){
392
                $color_index = imagecolorat($image,$i,$j);
393
                $colors = imagecolorsforindex($image,$color_index);
394
                imagesetpixel($destImage,abs($i-$w+1),$j,imagecolorallocate($destImage,$colors["red"],$colors["green"],$colors["blue"]));
395
            }
396
        }
397
        return $destImage;
398
    }
399
400
    /**
401
     * imageFlip
402
     * http://www.glic.co.jp/blog/archives/88 よりコピペ
403
     * 上下反転
404
     * @param resource $image
405
     * @return resource
406
     *
407
     * @author hagiwara
408
     */
409
    private function imageFlip($image)
410
    {
411
        // 画像の幅を取得
412
        $w = imagesx($image);
413
        // 画像の高さを取得
414
        $h = imagesy($image);
415
        // 変換後の画像の生成(元の画像と同じサイズ)
416
        $destImage = @imagecreatetruecolor($w,$h);
417
        // 逆側から色を取得
418
        for($i=0;$i<$w;$i++){
419
            for($j=($h-1);$j>=0;$j--){
420
                $color_index = imagecolorat($image,$i,$j);
421
                $colors = imagecolorsforindex($image,$color_index);
422
                imagesetpixel($destImage,$i,abs($j-$h+1),imagecolorallocate($destImage,$colors["red"],$colors["green"],$colors["blue"]));
423
            }
424
        }
425
        return $destImage;
426
    }
427
428
429
    /**
430
     * imageRotate
431
     * http://www.glic.co.jp/blog/archives/88 よりコピペ
432
     * 画像を回転
433
     * @param resouce $image
434
     * @param integer $angle
435
     * @param integer $bgd_color
436
     * @return resource
437
     *
438
     * @author hagiwara
439
     */
440
    private function imageRotate($image, int $angle, int $bgd_color)
441
    {
442
        return imagerotate($image, $angle, $bgd_color, 0);
443
    }
444
}
445