Completed
Push — master ( 6dabb1...ff07cf )
by satoru
03:05 queued 01:32
created

ContentsFileTrait::imageFlop()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 18
Code Lines 10

Duplication

Lines 18
Ratio 100 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 18
loc 18
rs 9.4285
cc 3
eloc 10
nc 3
nop 1
1
<?php
2
3
namespace ContentsFile\Model\Entity;
4
5
use Cake\Utility\Security;
6
use Cake\ORM\TableRegistry;
7
use Cake\I18n\Time;
8
use ContentsFile\Aws\S3;
9
use Cake\Network\Exception\InternalErrorException;
10
use Cake\Core\Configure;
11
use Cake\Filesystem\File;
12
13
trait ContentsFileTrait
14
{
15
    private $contentsFileSettings = [];
16
17
    /**
18
     * contentsFileSettings
19
     * 設定値のセッティング
20
     *
21
     * @author hagiwara
22
     */
23
    private function contentsFileSettings()
24
    {
25
        $default = [];
26
        //設定値はまとめる
27
        $settings = $this->contentsFileConfig;
0 ignored issues
show
Bug introduced by
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...
28
        $this->contentsFileSettings = array_merge($default, $settings);
29
    }
30
31
    /**
32
     * getContentsFileSettings
33
     * 設定値のセッティングの取得
34
     *
35
     * @author hagiwara
36
     */
37
    public function getContentsFileSettings()
38
    {
39
        if (empty($this->contentsFileSettings)) {
40
            $this->contentsFileSettings();
41
        }
42
        return $this->contentsFileSettings;
43
    }
44
45
    /**
46
     * getContentsFile
47
     * ファイルのgetterのセッティング
48
     *
49
     * @author hagiwara
50
     * @param string $property
51
     * @param array $value
52
     */
53
    public function getContentsFile($property, $value)
54
    {
55
        $this->contentsFileSettings();
56
        if (
57
            //attachmentにデータが登録時のみ
58
            !empty($this->id) &&
59
            //設定値に設定されているとき
60
            preg_match('/^contents_file_(.*)$/', $property, $match) &&
61
            array_key_exists($match[1], $this->contentsFileSettings['fields'])
62
        ) {
63
            //何もセットされていないとき
64
            if (empty($this->_properties[$property])) {
65
                //attachmentからデータを探しに行く
66
                $attachmentModel = TableRegistry::get('Attachments');
67
                $attachmentData = $attachmentModel->find('all')
68
                    ->where(['model' => $this->source()])
0 ignored issues
show
Bug introduced by
It seems like source() 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...
69
                    ->where(['model_id' => $this->id])
0 ignored issues
show
Bug introduced by
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...
70
                    ->where(['field_name' => $match[1]])
71
                    ->first()
72
                ;
73
                if (!empty($attachmentData)) {
74
                    $value = [
75
                        'model' => $attachmentData->model,
76
                        'model_id' => $attachmentData->model_id,
77
                        'field_name' => $attachmentData->field_name,
78
                        'file_name' => $attachmentData->file_name,
79
                        'file_content_type' => $attachmentData->file_content_type,
80
                        'file_size' => $attachmentData->file_size,
81
                        'file_random_path' => $attachmentData->file_random_path,
82
                    ];
83
                }
84
            } else {
85
                //それ以外はpropertiesの値を取得(setterで値を編集している場合はそれを反映するために必要)
86
                $value = $this->_properties[$property];
0 ignored issues
show
Bug introduced by
The property _properties 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...
87
            }
88
        }
89
        return $value;
90
    }
91
92
    /**
93
     * setContentsFile
94
     * ファイルのsetterのセッティング
95
     *
96
     * @author hagiwara
97
     */
98
    public function setContentsFile()
99
    {
100
        $this->contentsFileSettings();
101
        foreach ($this->contentsFileSettings['fields'] as $field => $fieldSetting) {
102
            // 通常のパターン
103
            if (!array_key_exists('type', $fieldSetting) || $fieldSetting['type'] == 'normal') {
104
                $this->normalSetContentsFile($field, $fieldSetting);
105
            } else {
106
                $this->ddSetContentsFile($field, $fieldSetting);
107
            }
108
        }
109
        return $this;
110
    }
111
112
    /**
113
     * normalSetContentsFile
114
     * ファイルのsetterのセッティング
115
     *
116
     * @author hagiwara
117
     */
118
    private function normalSetContentsFile($field, $fieldSetting)
119
    {
120
            $fileInfo = $this->{$field};
121
            if (
122
                //ファイルの情報がある
123
                !empty($fileInfo) &&
124
                //エラーのフィールドがある=ファイルをアップロード中
125
                array_key_exists('error', $fileInfo) &&
126
                //空アップロード時は通さない(もともとのデータを活かす)
127
                $fileInfo['error'] != UPLOAD_ERR_NO_FILE
128
            ) {
129
                $fileSet = [
130
                    'model' => $this->source(),
0 ignored issues
show
Bug introduced by
It seems like source() 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...
131
                    'model_id' => $this->id,
132
                    'field_name' => $field,
133
                    'file_name' => $fileInfo['name'],
134
                    'file_content_type' => Configure::read('ContentsFile.Setting.type'),
135
                    'file_size' => $fileInfo['size'],
136
                    'file_error' => $fileInfo['error'],
137
                ];
138
139
                //$fileInfoにtmp_nameがいるときはtmpディレクトリへのファイルのコピーを行う
140
                if (!empty($fileInfo['tmp_name'])) {
141
                    $tmpFileName = Security::hash(rand() . Time::now()->i18nFormat('YYYY/MM/dd HH:ii:ss') . $fileInfo['name']);
142
143
                    if ($this->getExt($fileInfo['name']) !== null) {
144
                        $tmpFileName .= '.' . $this->getExt($fileInfo['name']);
145
                    }
146
147
                    // tmpディレクトリへのアップロードのエラー(パーミッションなど)
148
                    if (!$this->tmpUpload($fileInfo['tmp_name'], $fieldSetting, $tmpFileName)) {
149
                        throw new InternalErrorException('tmp upload error');
150
                    }
151
                    $fileSet['tmp_file_name'] = $tmpFileName;
152
                }
153
                //これを残して次に引き渡したくないので
154
                unset($this->{$field});
155
156
                $this->{'contents_file_' . $field} = $fileSet;
157
                $this->{'contents_file_' . $field . '_filename'} = $fileInfo['name'];
158
            }
159
    }
160
161
    /**
162
     * ddSetContentsFile
163
     * ファイルのsetterのセッティング
164
     *
165
     * @author hagiwara
166
     */
167
    private function ddSetContentsFile($field, $fieldSetting)
168
    {
169
170
        $fileInfo = $this->{$field};
171
        if (!empty($fileInfo)) {
172
            if (!preg_match('/^data:([^;]+);base64,(.+)$/', $fileInfo, $fileMatch)) {
173
                // ちゃんとファイルアップがないのでエラー
174
                throw new InternalErrorException('tmp upload erroar');
175
            }
176
            $filename = $this->{'contents_file_' . $field . '_filename'};
177
178
            $filebody = base64_decode($fileMatch[2]);
179
            $filesize = strlen($filebody);
180
181
            $tmpFileName = Security::hash(rand() . Time::now()->i18nFormat('YYYY/MM/dd HH:ii:ss') . $filename);
182
183
            if ($this->getExt($filename) !== null) {
184
                $tmpFileName .= '.' . $this->getExt($filename);
185
            }
186
            // まずは一時的にファイルを書き出す
187
            $ddTmpFileName = TMP . Security::hash(rand() . Time::now()->i18nFormat('YYYY/MM/dd HH:ii:ss') . $filename);
188
            $fp = new File($ddTmpFileName);
189
            $fp->write($filebody);
190
191
            // tmpディレクトリへのアップロードのエラー(パーミッションなど)
192
            if (!$this->tmpUpload($ddTmpFileName, $fieldSetting, $tmpFileName)) {
193
                throw new InternalErrorException('tmp upload error');
194
            }
195
            $fp->delete();
196
            $fp->close();
197
198
            $fileSet = [
199
                'model' => $this->source(),
0 ignored issues
show
Bug introduced by
It seems like source() 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...
200
                'model_id' => $this->id,
201
                'field_name' => $field,
202
                'file_name' => $filename,
203
                'file_content_type' => Configure::read('ContentsFile.Setting.type'),
204
                'file_size' => $filesize,
205
                'file_error' => 0,
206
            ];
207
208
            $fileSet['tmp_file_name'] = $tmpFileName;
209
210
            //これを残して次に引き渡したくないので
211
            unset($this->{$field});
212
213
            $this->{'contents_file_' . $field} = $fileSet;
214
            $this->{'contents_file_' . $field . '_filename'} = $filename;
215
        }
216
    }
217
218
    /**
219
     * getExt
220
     * 拡張子の取得
221
     *
222
     * @author hagiwara
223
     * @param string $file
224
     */
225
    private function getExt($file)
226
    {
227
        $fileExplode = explode('.', $file);
228
        //この場合拡張子なし
229
        if (count($fileExplode) == 1) {
230
            return null;
231
        }
232
        return $fileExplode[(count($fileExplode) - 1)];
233
    }
234
235
    /**
236
     * tmpUpload
237
     * tmpディレクトリへのアップロード
238
     *
239
     * @author hagiwara
240
     * @param string $tmpFileName
241
     * @param array $fieldSetting
242
     * @param string $tmpFileName
243
     */
244
    private function tmpUpload($tmpName, $fieldSetting, $tmpFileName)
0 ignored issues
show
Unused Code introduced by
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...
245
    {
246
        // 向きの調整をする場合
247
        if (Configure::read('ContentsFile.Setting.exifRotate') == true) {
248
            $this->orientationFixedImage($tmpName, $tmpName);
249
        }
250
        // すでにtraitのため、ここはif文での分岐処理
251
        if (Configure::read('ContentsFile.Setting.type') == 'normal') {
252
            return copy($tmpName, Configure::read('ContentsFile.Setting.Normal.tmpDir') . $tmpFileName);
253
        } elseif (Configure::read('ContentsFile.Setting.type') == 's3') {
254
            $uploadFileName = Configure::read('ContentsFile.Setting.S3.tmpDir') . $tmpFileName;
255
            $S3 = new S3();
256
            return $S3->upload($tmpName, $uploadFileName);
257
        } else {
258
            throw new InternalErrorException('contentsFileConfig type illegal');
259
        }
260
    }
261
262
    /**
263
     * orientationFixedImage
264
     * http://www.glic.co.jp/blog/archives/88 よりコピペ
265
     * 画像の方向を正す
266
     * 向きだけロジックが逆そうなので調整
267
     *
268
     * @author hagiwara
269
     */
270
    private function orientationFixedImage($input, $output){
271
        $imagetype = exif_imagetype($input);
272
        // 何も取れない場合何もしない
273
        if ($imagetype === false) {
274
            return;
275
        }
276
        // exif情報の取得
277
        $exif_datas = @exif_read_data($input);
278
        // 画像読み込み
279 View Code Duplication
        switch ($imagetype) {
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...
280
            case IMAGETYPE_GIF:
281
                $image = ImageCreateFromGIF($input);
282
                break;
283
            case IMAGETYPE_JPEG:
284
                $image = ImageCreateFromJPEG($input);
285
                break;
286
            case IMAGETYPE_PNG:
287
                $image = ImageCreateFromPNG($input);
288
                break;
289
            default:
290
                $image = false;
291
        }
292
293
        // 画像以外は何もしない
294
        if (!$image) {
295
            return;
296
        }
297
298
        // 向き補正
299
        if(isset($exif_datas['Orientation'])){
300
            $orientation = $exif_datas['Orientation'];
301
            if($image){
302
                // 未定義
303
                if($orientation == 0) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
304
                    // 通常
305
                }else if($orientation == 1) {
0 ignored issues
show
Unused Code introduced by
This if statement is empty and can be removed.

This check looks for the bodies of if statements that have no statements or where all statements have been commented out. This may be the result of changes for debugging or the code may simply be obsolete.

These if bodies can be removed. If you have an empty if but statements in the else branch, consider inverting the condition.

if (rand(1, 6) > 3) {
//print "Check failed";
} else {
    print "Check succeeded";
}

could be turned into

if (rand(1, 6) <= 3) {
    print "Check succeeded";
}

This is much more concise to read.

Loading history...
306
                    // 左右反転
307
                }else if($orientation == 2) {
308
                    $image = $this->imageFlop($image);
309
                    // 180°回転
310
                }else if($orientation == 3) {
311
                    $image = $this->imageRotate($image,180, 0);
312
                    // 上下反転
313
                }else if($orientation == 4) {
314
                    $image = $this->imageFlip($image);
315
                    // 反時計回りに90°回転 上下反転
316
                }else if($orientation == 5) {
317
                    $image = $this->imageRotate($image,90, 0);
318
                    $image = $this->imageFlip($image);
319
                    // 時計回りに90°回転
320
                }else if($orientation == 6) {
321
                    $image = $this->imageRotate($image,-90, 0);
322
                    // 時計回りに90°回転 上下反転
323
                }else if($orientation == 7) {
324
                    $image = $this->imageRotate($image,-90, 0);
325
                    $image = $this->imageFlip($image);
326
                // 反時計回りに90°回転
327
                }else if($orientation == 8) {
328
                    $image = $this->imageRotate($image,90, 0);
329
                }
330
            }
331
        }
332
333
        switch ($imagetype) {
334
            case IMAGETYPE_GIF:
335
                ImageGIF($image ,$output);
336
                break;
337
            case IMAGETYPE_JPEG:
338
                ImageJPEG($image ,$output, 100);
339
                break;
340
            case IMAGETYPE_PNG:
341
                ImagePNG($image ,$output);
342
                break;
343
            default:
344
                return;
345
        }
346
    }
347
348
    /**
349
     * imageFlop
350
     * http://www.glic.co.jp/blog/archives/88 よりコピペ
351
     * 画像の左右反転
352
     *
353
     * @author hagiwara
354
     */
355 View Code Duplication
    private function imageFlop($image)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
356
    {
357
        // 画像の幅を取得
358
        $w = imagesx($image);
359
        // 画像の高さを取得
360
        $h = imagesy($image);
361
        // 変換後の画像の生成(元の画像と同じサイズ)
362
        $destImage = @imagecreatetruecolor($w,$h);
363
        // 逆側から色を取得
364
        for($i=($w-1);$i>=0;$i--){
365
            for($j=0;$j<$h;$j++){
366
                $color_index = imagecolorat($image,$i,$j);
367
                $colors = imagecolorsforindex($image,$color_index);
368
                imagesetpixel($destImage,abs($i-$w+1),$j,imagecolorallocate($destImage,$colors["red"],$colors["green"],$colors["blue"]));
369
            }
370
        }
371
        return $destImage;
372
    }
373
374
    /**
375
     * imageFlip
376
     * http://www.glic.co.jp/blog/archives/88 よりコピペ
377
     * 上下反転
378
     * @param resource $image
379
     *
380
     * @author hagiwara
381
     */
382 View Code Duplication
    private function imageFlip($image)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in 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...
383
    {
384
        // 画像の幅を取得
385
        $w = imagesx($image);
386
        // 画像の高さを取得
387
        $h = imagesy($image);
388
        // 変換後の画像の生成(元の画像と同じサイズ)
389
        $destImage = @imagecreatetruecolor($w,$h);
390
        // 逆側から色を取得
391
        for($i=0;$i<$w;$i++){
392
            for($j=($h-1);$j>=0;$j--){
393
                $color_index = imagecolorat($image,$i,$j);
394
                $colors = imagecolorsforindex($image,$color_index);
395
                imagesetpixel($destImage,$i,abs($j-$h+1),imagecolorallocate($destImage,$colors["red"],$colors["green"],$colors["blue"]));
396
            }
397
        }
398
        return $destImage;
399
    }
400
401
402
    /**
403
     * imageRotate
404
     * http://www.glic.co.jp/blog/archives/88 よりコピペ
405
     * 画像を回転
406
     * @param integer $angle
407
     * @param integer $bgd_color
408
     *
409
     * @author hagiwara
410
     */
411
    private function imageRotate($image, $angle, $bgd_color)
412
    {
413
        return imagerotate($image, $angle, $bgd_color, 0);
414
    }
415
}
416