myswap / 1 / code / ThinkPHP / Lib / ORG / Net / UploadFile_sae.class.php

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
<?php

// +----------------------------------------------------------------------
// | ThinkPHP [ WE CAN DO IT JUST THINK IT ]
// +----------------------------------------------------------------------
// | Copyright (c) 2009 http://thinkphp.cn All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: liu21st <liu21st@gmail.com>
// +----------------------------------------------------------------------
// $Id$

/**
  +------------------------------------------------------------------------------
 * 文件上传类
  +------------------------------------------------------------------------------
 * @category   ORG
 * @package  ORG
 * @subpackage  Net
 * @author    liu21st <liu21st@gmail.com>
 * @version   $Id$
  +------------------------------------------------------------------------------
 */
class UploadFile extends Think {//类定义开始
    // 上传文件的最大值

    public $maxSize = -1;
    // 是否支持多文件上传
    public $supportMulti = true;
    // 允许上传的文件后缀
    //  留空不作后缀检查
    public $allowExts = array();
    // 允许上传的文件类型
    // 留空不做检查
    public $allowTypes = array();
    // 使用对上传图片进行缩略图处理
    public $thumb = false;
    // 图库类包路径
    public $imageClassPath = 'ORG.Util.Image';
    // 缩略图最大宽度
    public $thumbMaxWidth;
    // 缩略图最大高度
    public $thumbMaxHeight;
    // 缩略图前缀
    public $thumbPrefix = 'thumb_';
    public $thumbSuffix = '';
    // 缩略图保存路径
    public $thumbPath = '';
    // 缩略图文件名
    public $thumbFile = '';
    // 是否移除原图
    public $thumbRemoveOrigin = false;
    // 压缩图片文件上传
    public $zipImages = false;
    // 启用子目录保存文件
    public $autoSub = false;
    // 子目录创建方式 可以使用hash date
    public $subType = 'hash';
    public $dateFormat = 'Ymd';
    public $hashLevel = 1; // hash的目录层次
    // 上传文件保存路径
    public $savePath = '';
    public $autoCheck = true; // 是否自动检查附件
    // 存在同名是否覆盖
    public $uploadReplace = false;
    // 上传文件命名规则
    // 例如可以是 time uniqid com_create_guid 等
    // 必须是一个无需任何参数的函数名 可以使用自定义函数
    public $saveRule = '';
    // 上传文件Hash规则函数名
    // 例如可以是 md5_file sha1_file 等
    public $hashType = 'md5_file';
    // 错误信息
    private $error = '';
    //saestorage对象
    protected $storage;
    //存储saestorage的domain
    protected $domain;
    // 上传成功的文件信息
    private $uploadFileInfo;

    /**
      +----------------------------------------------------------
     * 架构函数
      +----------------------------------------------------------
     * @access public
      +----------------------------------------------------------
     */
    public function __construct($maxSize='', $allowExts='', $allowTypes='', $savePath='', $saveRule='') {
        if (!empty($maxSize) && is_numeric($maxSize)) {
            $this->maxSize = $maxSize;
        }
        if (!empty($allowExts)) {
            if (is_array($allowExts)) {
                $this->allowExts = array_map('strtolower', $allowExts);
            } else {
                $this->allowExts = explode(',', strtolower($allowExts));
            }
        }
        if (!empty($allowTypes)) {
            if (is_array($allowTypes)) {
                $this->allowTypes = array_map('strtolower', $allowTypes);
            } else {
                $this->allowTypes = explode(',', strtolower($allowTypes));
            }
        }
        if (!empty($saveRule)) {
            $this->saveRule = $saveRule;
        } else {
            $this->saveRule = C('UPLOAD_FILE_RULE');
        }
        $this->savePath = $savePath;
        $this->storage = new SaeStorage();
    }

    /**
      +----------------------------------------------------------
     * 上传一个文件
      +----------------------------------------------------------
     * @access public
      +----------------------------------------------------------
     * @param mixed $name 数据
     * @param string $value  数据表名
      +----------------------------------------------------------
     * @return string
      +----------------------------------------------------------
     * @throws ThinkExecption
      +----------------------------------------------------------
     */
    private function save($file) {
        $filename = $file['savepath'] . $file['savename'];
        $domain = $this->domain;
        $filen = $file['savename'];
        if ($this->storage->fileExists($domain, $filen) && !$this->uploadReplace) {
            $this->error = '文件已经存在!' . $filen;
            return false;
        }
        // 如果是图像文件 检测文件格式
        if (in_array(strtolower($file['extension']), array('gif', 'jpg', 'jpeg', 'bmp', 'png', 'swf')) && false === getimagesize($file['tmp_name'])) {
            $this->error = '非法图像文件';
            return false;
        }
        $savepath = $this->storage->upload($domain, auto_charset($filen, 'utf-8', 'gbk'), $file['tmp_name']);
        if (!$savepath) {
            $err = $this->storage->errno();
            if ($err == -7) {
                $errstr = 'domain [ ' . $domain . ' ] 不存在!请在SAE控制台的Storage服务中添加一个domain';
            } else {
                $errstr = "文件上传保存错误!";
            }
            $this->error = $errstr;
            return false;
        }
        if ($this->thumb && in_array(strtolower($file['extension']), array('gif', 'jpg', 'jpeg', 'bmp', 'png'))) {
            $image = getimagesize($file['tmp_name']);
            if (false !== $image) {
                //是图像文件生成缩略图
                $thumbWidth = explode(',', $this->thumbMaxWidth);
                $thumbHeight = explode(',', $this->thumbMaxHeight);
                $thumbPrefix = explode(',', $this->thumbPrefix);
                $thumbSuffix = explode(',', $this->thumbSuffix);
                $thumbFile = explode(',', $this->thumbFile);
                $thumbPath = $this->thumbPath ? $this->thumbPath : $file['savepath'];
                // 生成图像缩略图
                $realFilename = $this->autoSub ? basename($file['savename']) : $file['savename'];
                $srcWidth = $image[0];
                $srcHeight = $image[1];
                 $img = new SaeImage();
                for ($i = 0, $len = count($thumbWidth); $i < $len; $i++) {
                    $scale = min($thumbWidth[$i] / $srcWidth, $thumbHeight[$i] / $srcHeight); // 计算缩放比例
                    if ($scale >= 1) {
                        // 超过原图大小不再缩略
                        $width = $srcWidth;
                        $height = $srcHeight;
                    } else {
                        // 缩略图尺寸
                        $width = (int) ($srcWidth * $scale);
                        $height = (int) ($srcHeight * $scale);
                    }
                    $thumbname = $thumbPrefix[$i] . substr($realFilename, 0, strrpos($realFilename, '.')) . $thumbSuffix[$i] . '.' . $file['extension'];
                    $img->setData(file_get_contents($file['tmp_name']));
                    $img->resize($width, $height);
                    $new_data = $img->exec();
                    $this->storage->write($domain, $thumbname, $new_data);
                }
                if ($this->thumbRemoveOrigin) {
                    // 生成缩略图之后删除原图
                    $this->storage->delete($domain, $filen);
                }
            }
        }
        if ($this->zipImags) {
            // TODO 对图片压缩包在线解压
        }
        return true;
    }

    /**
      +----------------------------------------------------------
     * 上传所有文件
      +----------------------------------------------------------
     * @access public
      +----------------------------------------------------------
     * @param string $savePath  上传文件保存路径
      +----------------------------------------------------------
     * @return string
      +----------------------------------------------------------
     * @throws ThinkExecption
      +----------------------------------------------------------
     */
    public function upload($savePath ='') {
        //如果不指定保存文件名,则由系统默认
        if (empty($savePath))
            $savePath = $this->savePath;
        // 获得domain
        $arr = sae_parse_path($savePath);
        $this->domain = $arr['domain'];
        $fileInfo = array();
        $isUpload = false;

        // 获取上传的文件信息
        // 对$_FILES数组信息处理
        $files = $this->dealFiles($_FILES);
        foreach ($files as $key => $file) {
            //过滤无效的上传
            if (!empty($file['name'])) {
                //登记上传文件的扩展信息
                $file['key'] = $key;
                $file['extension'] = $this->getExt($file['name']);
                $file['savepath'] = $savePath;
                $file['savename'] = $this->getSaveName($file);

                // 自动检查附件
                if ($this->autoCheck) {
                    if (!$this->check($file))
                        return false;
                }

                //保存上传文件
                if (!$this->save($file))
                    return false;
                if (function_exists($this->hashType)) {
                    $fun = $this->hashType;
                    $file['hash'] = $fun(auto_charset($file['savepath'] . $file['savename'], 'utf-8', 'gbk'));
                }
                //上传成功后保存文件信息,供其他地方调用
                unset($file['tmp_name'], $file['error']);
                $fileInfo[] = $file;
                $isUpload = true;
            }
        }
        if ($isUpload) {
            $this->uploadFileInfo = $fileInfo;
            return true;
        } else {
            $this->error = '没有选择上传文件';
            return false;
        }
    }

    /**
      +----------------------------------------------------------
     * 上传单个上传字段中的文件 支持多附件
      +----------------------------------------------------------
     * @access public
      +----------------------------------------------------------
     * @param array $file  上传文件信息
     * @param string $savePath  上传文件保存路径
      +----------------------------------------------------------
     * @return string
      +----------------------------------------------------------
     * @throws ThinkExecption
      +----------------------------------------------------------
     */
    public function uploadOne($file, $savePath='') {
        //如果不指定保存文件名,则由系统默认
        if (empty($savePath))
            $savePath = $this->savePath;
        // 获得domain
        $arr = sae_parse_path($savePath);
        $this->domain = $arr['domain'];
        //过滤无效的上传
        if (!empty($file['name'])) {
            $fileArray = array();
            if (is_array($file['name'])) {
                $keys = array_keys($file);
                $count = count($file['name']);
                for ($i = 0; $i < $count; $i++) {
                    foreach ($keys as $key)
                        $fileArray[$i][$key] = $file[$key][$i];
                }
            } else {
                $fileArray[] = $file;
            }
            $info = array();
            foreach ($fileArray as $key => $file) {
                //登记上传文件的扩展信息
                $file['extension'] = $this->getExt($file['name']);
                $file['savepath'] = $savePath;
                $file['savename'] = $this->getSaveName($file);
                // 自动检查附件
                if ($this->autoCheck) {
                    if (!$this->check($file))
                        return false;
                }
                //保存上传文件
                if (!$this->save($file))
                    return false;
                if (function_exists($this->hashType)) {
                    $fun = $this->hashType;
                    $file['hash'] = $fun(auto_charset($file['savepath'] . $file['savename'], 'utf-8', 'gbk'));
                }
                unset($file['tmp_name'], $file['error']);
                $info[] = $file;
            }
            // 返回上传的文件信息
            return $info;
        } else {
            $this->error = '没有选择上传文件';
            return false;
        }
    }

    /**
      +----------------------------------------------------------
     * 转换上传文件数组变量为正确的方式
      +----------------------------------------------------------
     * @access private
      +----------------------------------------------------------
     * @param array $files  上传的文件变量
      +----------------------------------------------------------
     * @return array
      +----------------------------------------------------------
     */
    private function dealFiles($files) {
        $fileArray = array();
        $n = 0;
        foreach ($files as $file) {
            if (is_array($file['name'])) {
                $keys = array_keys($file);
                $count = count($file['name']);
                for ($i = 0; $i < $count; $i++) {
                    foreach ($keys as $key)
                        $fileArray[$n][$key] = $file[$key][$i];
                    $n++;
                }
            } else {
                $fileArray[$n] = $file;
                $n++;
            }
        }
        return $fileArray;
    }

    /**
      +----------------------------------------------------------
     * 获取错误代码信息
      +----------------------------------------------------------
     * @access public
      +----------------------------------------------------------
     * @param string $errorNo  错误号码
      +----------------------------------------------------------
     * @return void
      +----------------------------------------------------------
     * @throws ThinkExecption
      +----------------------------------------------------------
     */
    protected function error($errorNo) {
        switch ($errorNo) {
            case 1:
                $this->error = '上传的文件超过了 php.ini 中 upload_max_filesize 选项限制的值';
                break;
            case 2:
                $this->error = '上传文件的大小超过了 HTML 表单中 MAX_FILE_SIZE 选项指定的值';
                break;
            case 3:
                $this->error = '文件只有部分被上传';
                break;
            case 4:
                $this->error = '没有文件被上传';
                break;
            case 6:
                $this->error = '找不到临时文件夹';
                break;
            case 7:
                $this->error = '文件写入失败';
                break;
            default:
                $this->error = '未知上传错误!';
        }
        return;
    }

    /**
      +----------------------------------------------------------
     * 根据上传文件命名规则取得保存文件名
      +----------------------------------------------------------
     * @access private
      +----------------------------------------------------------
     * @param string $filename 数据
      +----------------------------------------------------------
     * @return string
      +----------------------------------------------------------
     */
    private function getSaveName($filename) {
        $rule = $this->saveRule;
        if (empty($rule)) {//没有定义命名规则,则保持文件名不变
            $saveName = $filename['name'];
        } else {
            if (function_exists($rule)) {
                //使用函数生成一个唯一文件标识号
                $saveName = $rule() . "." . $filename['extension'];
            } else {
                //使用给定的文件名作为标识号
                $saveName = $rule . "." . $filename['extension'];
            }
        }
        if ($this->autoSub) {
            // 使用子目录保存文件
            $filename['savename'] = $saveName;
            $saveName = $this->getSubName($filename) . '/' . $saveName;
        }
        return $saveName;
    }

    /**
      +----------------------------------------------------------
     * 获取子目录的名称
      +----------------------------------------------------------
     * @access private
      +----------------------------------------------------------
     * @param array $file  上传的文件信息
      +----------------------------------------------------------
     * @return string
      +----------------------------------------------------------
     */
    private function getSubName($file) {
        switch ($this->subType) {
            case 'date':
                $dir = date($this->dateFormat, time());
                break;
            case 'hash':
            default:
                $name = md5($file['savename']);
                $dir = '';
                for ($i = 0; $i < $this->hashLevel; $i++) {
                    $dir .= $name{$i} . '/';
                }
                break;
        }
        if (!is_dir($file['savepath'] . $dir)) {
            mk_dir($file['savepath'] . $dir);
        }
        return $dir;
    }

    /**
      +----------------------------------------------------------
     * 检查上传的文件
      +----------------------------------------------------------
     * @access private
      +----------------------------------------------------------
     * @param array $file 文件信息
      +----------------------------------------------------------
     * @return boolean
      +----------------------------------------------------------
     */
    private function check($file) {
        if ($file['error'] !== 0) {
            //文件上传失败
            //捕获错误代码
            $this->error($file['error']);
            return false;
        }
        //文件上传成功,进行自定义规则检查
        //检查文件大小
        if (!$this->checkSize($file['size'])) {
            $this->error = '上传文件大小不符!';
            return false;
        }

        //检查文件Mime类型
        if (!$this->checkType($file['type'])) {
            $this->error = '上传文件MIME类型不允许!';
            return false;
        }
        //检查文件类型
        if (!$this->checkExt($file['extension'])) {
            $this->error = '上传文件类型不允许';
            return false;
        }

        //检查是否合法上传
        if (!$this->checkUpload($file['tmp_name'])) {
            $this->error = '非法上传文件!';
            return false;
        }
        return true;
    }

    /**
      +----------------------------------------------------------
     * 检查上传的文件类型是否合法
      +----------------------------------------------------------
     * @access private
      +----------------------------------------------------------
     * @param string $type 数据
      +----------------------------------------------------------
     * @return boolean
      +----------------------------------------------------------
     */
    private function checkType($type) {
        if (!empty($this->allowTypes))
            return in_array(strtolower($type), $this->allowTypes);
        return true;
    }

    /**
      +----------------------------------------------------------
     * 检查上传的文件后缀是否合法
      +----------------------------------------------------------
     * @access private
      +----------------------------------------------------------
     * @param string $ext 后缀名
      +----------------------------------------------------------
     * @return boolean
      +----------------------------------------------------------
     */
    private function checkExt($ext) {
        if (!empty($this->allowExts))
            return in_array(strtolower($ext), $this->allowExts, true);
        return true;
    }

    /**
      +----------------------------------------------------------
     * 检查文件大小是否合法
      +----------------------------------------------------------
     * @access private
      +----------------------------------------------------------
     * @param integer $size 数据
      +----------------------------------------------------------
     * @return boolean
      +----------------------------------------------------------
     */
    private function checkSize($size) {
        return!($size > $this->maxSize) || (-1 == $this->maxSize);
    }

    /**
      +----------------------------------------------------------
     * 检查文件是否非法提交
      +----------------------------------------------------------
     * @access private
      +----------------------------------------------------------
     * @param string $filename 文件名
      +----------------------------------------------------------
     * @return boolean
      +----------------------------------------------------------
     */
    private function checkUpload($filename) {
        return is_uploaded_file($filename);
    }

    /**
      +----------------------------------------------------------
     * 取得上传文件的后缀
      +----------------------------------------------------------
     * @access private
      +----------------------------------------------------------
     * @param string $filename 文件名
      +----------------------------------------------------------
     * @return boolean
      +----------------------------------------------------------
     */
    private function getExt($filename) {
        $pathinfo = pathinfo($filename);
        return $pathinfo['extension'];
    }

    /**
      +----------------------------------------------------------
     * 取得上传文件的信息
      +----------------------------------------------------------
     * @access public
      +----------------------------------------------------------
     * @return array
      +----------------------------------------------------------
     */
    public function getUploadFileInfo() {
        return $this->uploadFileInfo;
    }

    /**
      +----------------------------------------------------------
     * 取得最后一次错误信息
      +----------------------------------------------------------
     * @access public
      +----------------------------------------------------------
     * @return string
      +----------------------------------------------------------
     */
    public function getErrorMsg() {
        return $this->error;
    }

}

//类定义结束
?>
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.