Image.php 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310
  1. <?php
  2. /*
  3. * FecShop file.
  4. *
  5. * @link http://www.fecshop.com/
  6. * @copyright Copyright (c) 2016 FecShop Software LLC
  7. * @license http://www.fecshop.com/license/
  8. */
  9. namespace fecshop\services;
  10. use fec\helpers\CDir;
  11. use Yii;
  12. use yii\base\InvalidValueException;
  13. /**
  14. * Image services.
  15. * @author Terry Zhao <2358269014@qq.com>
  16. * @since 1.0
  17. */
  18. class Image extends Service
  19. {
  20. /**
  21. * absolute image save floder.
  22. */
  23. public $imageFloder = 'media/upload';
  24. /**
  25. * upload image max size (MB).
  26. */
  27. public $maxUploadMSize = 2;
  28. /**
  29. * allow image type.
  30. */
  31. public $allowImgType = [
  32. 'image/jpeg',
  33. 'image/gif',
  34. 'image/png',
  35. 'image/jpg',
  36. 'image/pjpeg',
  37. ];
  38. protected $_maxUploadSize;
  39. // public $appbase;
  40. public $commonBaseDir;
  41. public $commonBaseDomain;
  42. /**
  43. * @param $file | string, 图片文件路径
  44. * @return boolean, 是否是允许的图片类型
  45. */
  46. public function isAllowImgType($file, $fileName)
  47. {
  48. $img = getimagesize($file);
  49. $imgType = $img['mime'];
  50. if (!in_array($imgType, $this->allowImgType)) {
  51. return false;
  52. }
  53. // 文件后缀检查
  54. $fileNameArr = explode('.', $fileName);
  55. $fileSuffix = $fileNameArr[count($fileNameArr)-1];
  56. $allowImgSuffix = $this->getAllowImgSuffix();
  57. if (!in_array($fileSuffix, $allowImgSuffix)) {
  58. return false;
  59. }
  60. return true;
  61. }
  62. public function getAllowImgSuffix()
  63. {
  64. $arr = [];
  65. if (!is_array($this->allowImgType) || empty($this->allowImgType)) {
  66. return [];
  67. }
  68. foreach ($this->allowImgType as $one) {
  69. $oneArr = explode('/',$one);
  70. $arr[] = $oneArr[1];
  71. }
  72. return $arr;
  73. }
  74. public function init()
  75. {
  76. parent::init();
  77. $this->commonBaseDomain = Yii::$app->store->get('base_info', 'image_domain');
  78. }
  79. /**
  80. * @param $str | String 图片的相对路径
  81. * @param $app | String @appimage下面的文件夹的名称。各个名称对应各个入口的名字,譬如common appfront appadmin等
  82. * @return 返回图片的绝对路径。
  83. */
  84. protected function actionGetImgDir($str = '') // , $app = 'common' 第二个参数废弃
  85. {
  86. if ($str) {
  87. return Yii::getAlias($this->commonBaseDir) . '/'.$str;
  88. }
  89. return Yii::getAlias($this->commonBaseDir);
  90. }
  91. /**
  92. * @param $str | String 图片的相对路径
  93. * @param $app | String @appimage下面的文件夹的名称。各个名称对应各个入口的名字,譬如common appfront appadmin等
  94. * @return 返回图片的完整URL
  95. */
  96. protected function actionGetImgUrl($str) // , $app = 'common' 第二个参数废弃
  97. {
  98. if ($str) {
  99. return $this->commonBaseDomain.'/'.$str;
  100. }
  101. return $this->commonBaseDomain;
  102. }
  103. /**
  104. * @param $app | String @appimage下面的文件夹的名称。各个名称对应各个入口的名字,譬如common appfront appadmin等
  105. * @return 返回图片存放目录的绝对路径。
  106. */
  107. protected function actionGetBaseImgDir($app = 'common')
  108. {
  109. return $this->getImgDir('', $app);
  110. }
  111. /**
  112. * @param $app | String @appimage下面的文件夹的名称。各个名称对应各个入口的名字,譬如common appfront appadmin等
  113. * @return 返回图片存放目录的URL
  114. */
  115. protected function actionGetBaseImgUrl($app = 'common')
  116. {
  117. return $this->getImgUrl('', $app);
  118. }
  119. /**
  120. * @param $uploadSize | Int , 多少MB
  121. * 设置上传图片的最大的size. 参数单位为MB
  122. */
  123. protected function actionSetMaxUploadSize($uploadSize)
  124. {
  125. $this->_maxUploadSize = $uploadSize * 1024 * 1024;
  126. }
  127. /**
  128. * 得到上传图片的最大的size.
  129. */
  130. protected function actionGetMaxUploadSize()
  131. {
  132. if (!$this->_maxUploadSize) {
  133. if ($this->maxUploadMSize) {
  134. $this->_maxUploadSize = $this->maxUploadMSize * 1024 * 1024;
  135. }
  136. }
  137. return $this->_maxUploadSize;
  138. }
  139. /**
  140. * 得到(上传)保存图片所在相对根目录的url路径.
  141. */
  142. protected function actionGetCurrentBaseImgUrl()
  143. {
  144. return $this->GetImgUrl($this->imageFloder, 'common');
  145. }
  146. /**
  147. * 得到(上传)保存图片所在相对根目录的文件夹路径.
  148. */
  149. protected function actionGetCurrentBaseImgDir()
  150. {
  151. return $this->GetImgDir($this->imageFloder, 'common');
  152. }
  153. /**
  154. * @param $str | String , 图片的相对路径字符串
  155. * 通过图片的相对路径得到产品图片的url.
  156. */
  157. protected function actionGetUrlByRelativePath($str)
  158. {
  159. return $this->GetImgUrl($this->imageFloder.$str, 'common');
  160. }
  161. /**
  162. * @param $str | String , 图片的相对路径字符串
  163. * 通过图片的相对路径得到产品图片的绝对路径.
  164. */
  165. protected function actionGetDirByRelativePath($str)
  166. {
  167. return $this->GetImgDir($this->imageFloder.$str, 'common');
  168. }
  169. /**
  170. * @param $name | String , 图片的原始名字,也就是图片上传的时候的名字。
  171. * @param $length | String , 生成图片随机字符的长度。
  172. * 随机生成图片的新名字,因为有的图片名字可能是中文或者其他语言,而fecshop在保存名字的时候会取名字的前2个字母生成2层文件夹
  173. * 这样中文名字就会出现问题,因此需要使用随机生成的名字(生成2层文件夹,是为了让文件夹下面不至于太多的文件,linux文件夹下的文件超过几万个,查找文件就会有点慢,这样做是为了避免这个文件。)
  174. */
  175. protected function generateImgName($name, $length = 15)
  176. {
  177. $arr = explode('.', $name);
  178. $fileType = '.'.$arr[count($arr)-1];
  179. // 密码字符集,可任意添加你需要的字符
  180. $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
  181. $str ='';
  182. for ($i = 0; $i < $length; $i++) {
  183. // 这里提供两种字符获取方式
  184. // 第一种是使用 substr 截取$chars中的任意一位字符;
  185. // 第二种是取字符数组 $chars 的任意元素
  186. // $str .= substr($chars, mt_rand(0, strlen($chars) – 1), 1);
  187. $str .= $chars[ mt_rand(0, strlen($chars) - 1) ];
  188. }
  189. $str .= time();
  190. return $str.$fileType;
  191. }
  192. /**
  193. * @param $param_img_file | Array .
  194. * 上传产品图片,
  195. * 如果成功,保存产品相对路径,譬如: '/b/i/big.jpg'
  196. * 如果失败,reutrn false;
  197. */
  198. protected function actionSaveUploadImg($FILE)
  199. {
  200. $size = $FILE['size'];
  201. $file = $FILE['tmp_name'];
  202. $name = $FILE['name'];
  203. $newName = $this->generateImgName($name);
  204. if (!$newName) {
  205. throw new InvalidValueException('generate img name fail');
  206. }
  207. if ($size > $this->getMaxUploadSize()) {
  208. throw new InvalidValueException('upload image is to max than'. $this->getMaxUploadSize().' MB');
  209. } elseif (!($img = getimagesize($file))) {
  210. throw new InvalidValueException('file type is empty.');
  211. } elseif ($img = getimagesize($file)) {
  212. $imgType = $img['mime'];
  213. if (!$this->isAllowImgType($file, $name)) {
  214. throw new InvalidValueException('image type is not allow for '.$imgType);
  215. }
  216. }
  217. // process image name.
  218. $imgSavedRelativePath = $this->getImgSavedRelativePath($newName);
  219. $isMoved = @move_uploaded_file($file, $this->GetCurrentBaseImgDir().$imgSavedRelativePath);
  220. if ($isMoved) {
  221. $imgUrl = $this->getUrlByRelativePath($imgSavedRelativePath);
  222. $imgPath = $this->getDirByRelativePath($imgSavedRelativePath);
  223. return [$imgSavedRelativePath, $imgUrl, $imgPath];
  224. } else {
  225. return false;
  226. }
  227. }
  228. /**
  229. * get Image save file path, if floder is not exist, this function will create floder.
  230. * if image file is exsit , image file name will be change to a not existed file name( by add radom string to file name ).
  231. * return image saved relative path , like /a/d/advert.jpg.
  232. */
  233. protected function getImgSavedRelativePath($name)
  234. {
  235. list($imgName, $imgType) = explode('.', $name);
  236. if (!$imgName || !$imgType) {
  237. throw new InvalidValueException('image file name and type is not correct');
  238. }
  239. if (strlen($imgName) < 2) {
  240. $imgName .= time(). mt_rand(100, 999);
  241. }
  242. $first_str = substr($imgName, 0, 1);
  243. $two_str = substr($imgName, 1, 2);
  244. $imgSaveFloder = CDir::createFloder($this->GetCurrentBaseImgDir(), [$first_str, $two_str]);
  245. if ($imgSaveFloder) {
  246. $imgName = $this->getUniqueImgNameInPath($imgSaveFloder, $imgName, $imgType);
  247. $relative_floder = '/'.$first_str.'/'.$two_str.'/';
  248. return $relative_floder.$imgName;
  249. }
  250. return false;
  251. }
  252. /**
  253. * @param $imgSaveFloder|string image save Floder absolute Path
  254. * @param $name|string , image file name ,not contain image suffix.
  255. * @param $imageType|string , image file suffix. like '.gif','jpg'
  256. * return saved Image Name.
  257. * 得到产品保存的唯一路径,因为可能存在名字重复的问题,因此使用该函数确保图片路径唯一。
  258. */
  259. protected function getUniqueImgNameInPath($imgSaveFloder, $name, $imageType, $randStr = '')
  260. {
  261. $imagePath = $imgSaveFloder.'/'.$name.$randStr.'.'.$imageType;
  262. if (!file_exists($imagePath)) {
  263. return $name.$randStr.'.'.$imageType;
  264. } else {
  265. $randStr = time().rand(10000, 99999);
  266. return $this->getUniqueImgNameInPath($imgSaveFloder, $name, $imageType, $randStr);
  267. }
  268. }
  269. }