Image.php 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  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. /**
  41. * @param $str | String 图片的相对路径
  42. * @param $app | String @appimage下面的文件夹的名称。各个名称对应各个入口的名字,譬如common appfront appadmin等
  43. * @return 返回图片的绝对路径。
  44. */
  45. protected function actionGetImgDir($str = '', $app = 'common')
  46. {
  47. if ($appbase = $this->appbase) {
  48. if (isset($appbase[$app]['basedir'])) {
  49. if ($str) {
  50. return Yii::getAlias($appbase[$app]['basedir'].'/'.$str);
  51. }
  52. return Yii::getAlias($appbase[$app]['basedir']);
  53. }
  54. }
  55. }
  56. /**
  57. * @param $str | String 图片的相对路径
  58. * @param $app | String @appimage下面的文件夹的名称。各个名称对应各个入口的名字,譬如common appfront appadmin等
  59. * @return 返回图片的完整URL
  60. */
  61. protected function actionGetImgUrl($str, $app = 'common')
  62. {
  63. //echo "$str,$app";
  64. if ($appbase = $this->appbase) {
  65. if (isset($appbase[$app]['basedomain'])) {
  66. if ($str) {
  67. return $appbase[$app]['basedomain'].'/'.$str;
  68. }
  69. return $appbase[$app]['basedomain'];
  70. }
  71. }
  72. }
  73. /**
  74. * @param $app | String @appimage下面的文件夹的名称。各个名称对应各个入口的名字,譬如common appfront appadmin等
  75. * @return 返回图片存放目录的绝对路径。
  76. */
  77. protected function actionGetBaseImgDir($app = 'common')
  78. {
  79. return $this->getImgDir('', $app);
  80. }
  81. /**
  82. * @param $app | String @appimage下面的文件夹的名称。各个名称对应各个入口的名字,譬如common appfront appadmin等
  83. * @return 返回图片存放目录的URL
  84. */
  85. protected function actionGetBaseImgUrl($app = 'common')
  86. {
  87. return $this->getImgUrl('', $app);
  88. }
  89. /**
  90. * @param $uploadSize | Int , 多少MB
  91. * 设置上传图片的最大的size. 参数单位为MB
  92. */
  93. protected function actionSetMaxUploadSize($uploadSize)
  94. {
  95. $this->_maxUploadSize = $uploadSize * 1024 * 1024;
  96. }
  97. /**
  98. * 得到上传图片的最大的size.
  99. */
  100. protected function actionGetMaxUploadSize()
  101. {
  102. if (!$this->_maxUploadSize) {
  103. if ($this->maxUploadMSize) {
  104. $this->_maxUploadSize = $this->maxUploadMSize * 1024 * 1024;
  105. }
  106. }
  107. return $this->_maxUploadSize;
  108. }
  109. /**
  110. * 得到(上传)保存图片所在相对根目录的url路径.
  111. */
  112. protected function actionGetCurrentBaseImgUrl()
  113. {
  114. return $this->GetImgUrl($this->imageFloder, 'common');
  115. }
  116. /**
  117. * 得到(上传)保存图片所在相对根目录的文件夹路径.
  118. */
  119. protected function actionGetCurrentBaseImgDir()
  120. {
  121. return $this->GetImgDir($this->imageFloder, 'common');
  122. }
  123. /**
  124. * @param $str | String , 图片的相对路径字符串
  125. * 通过图片的相对路径得到产品图片的url.
  126. */
  127. protected function actionGetUrlByRelativePath($str)
  128. {
  129. return $this->GetImgUrl($this->imageFloder.$str, 'common');
  130. }
  131. /**
  132. * @param $str | String , 图片的相对路径字符串
  133. * 通过图片的相对路径得到产品图片的绝对路径.
  134. */
  135. protected function actionGetDirByRelativePath($str)
  136. {
  137. return $this->GetImgDir($this->imageFloder.$str, 'common');
  138. }
  139. /**
  140. * @param $name | String , 图片的原始名字,也就是图片上传的时候的名字。
  141. * @param $length | String , 生成图片随机字符的长度。
  142. * 随机生成图片的新名字,因为有的图片名字可能是中文或者其他语言,而fecshop在保存名字的时候会取名字的前2个字母生成2层文件夹
  143. * 这样中文名字就会出现问题,因此需要使用随机生成的名字(生成2层文件夹,是为了让文件夹下面不至于太多的文件,linux文件夹下的文件超过几万个,查找文件就会有点慢,这样做是为了避免这个文件。)
  144. */
  145. protected function generateImgName($name, $length = 15)
  146. {
  147. $arr = explode('.', $name);
  148. $fileType = '.'.$arr[count($arr)-1];
  149. // 密码字符集,可任意添加你需要的字符
  150. $chars = 'abcdefghijklmnopqrstuvwxyz0123456789';
  151. $str ='';
  152. for ($i = 0; $i < $length; $i++) {
  153. // 这里提供两种字符获取方式
  154. // 第一种是使用 substr 截取$chars中的任意一位字符;
  155. // 第二种是取字符数组 $chars 的任意元素
  156. // $str .= substr($chars, mt_rand(0, strlen($chars) – 1), 1);
  157. $str .= $chars[ mt_rand(0, strlen($chars) - 1) ];
  158. }
  159. $str .= time();
  160. return $str.$fileType;
  161. }
  162. /**
  163. * @param $param_img_file | Array .
  164. * 上传产品图片,
  165. * 如果成功,保存产品相对路径,譬如: '/b/i/big.jpg'
  166. * 如果失败,reutrn false;
  167. */
  168. protected function actionSaveUploadImg($FILE)
  169. {
  170. $size = $FILE['size'];
  171. $file = $FILE['tmp_name'];
  172. $name = $FILE['name'];
  173. $name = $this->generateImgName($name);
  174. if ($size > $this->getMaxUploadSize()) {
  175. throw new InvalidValueException('upload image is to max than'. $this->getMaxUploadSize().' MB');
  176. } elseif (!($img = getimagesize($file))) {
  177. throw new InvalidValueException('file type is empty.');
  178. } elseif ($img = getimagesize($file)) {
  179. $imgType = $img['mime'];
  180. if (!in_array($imgType, $this->allowImgType)) {
  181. throw new InvalidValueException('image type is not allow for '.$imgType);
  182. }
  183. }
  184. // process image name.
  185. $imgSavedRelativePath = $this->getImgSavedRelativePath($name);
  186. $isMoved = @move_uploaded_file($file, $this->GetCurrentBaseImgDir().$imgSavedRelativePath);
  187. if ($isMoved) {
  188. $imgUrl = $this->getUrlByRelativePath($imgSavedRelativePath);
  189. $imgPath = $this->getDirByRelativePath($imgSavedRelativePath);
  190. return [$imgSavedRelativePath, $imgUrl, $imgPath];
  191. } else {
  192. return false;
  193. }
  194. }
  195. /**
  196. * get Image save file path, if floder is not exist, this function will create floder.
  197. * if image file is exsit , image file name will be change to a not existed file name( by add radom string to file name ).
  198. * return image saved relative path , like /a/d/advert.jpg.
  199. */
  200. protected function getImgSavedRelativePath($name)
  201. {
  202. list($imgName, $imgType) = explode('.', $name);
  203. if (!$imgName || !$imgType) {
  204. throw new InvalidValueException('image file name and type is not correct');
  205. }
  206. if (strlen($imgName) < 2) {
  207. $imgName .= time(). mt_rand(100, 999);
  208. }
  209. $first_str = substr($imgName, 0, 1);
  210. $two_str = substr($imgName, 1, 2);
  211. $imgSaveFloder = CDir::createFloder($this->GetCurrentBaseImgDir(), [$first_str, $two_str]);
  212. if ($imgSaveFloder) {
  213. $imgName = $this->getUniqueImgNameInPath($imgSaveFloder, $imgName, $imgType);
  214. $relative_floder = '/'.$first_str.'/'.$two_str.'/';
  215. return $relative_floder.$imgName;
  216. }
  217. return false;
  218. }
  219. /**
  220. * @param $imgSaveFloder|string image save Floder absolute Path
  221. * @param $name|string , image file name ,not contain image suffix.
  222. * @param $imageType|string , image file suffix. like '.gif','jpg'
  223. * return saved Image Name.
  224. * 得到产品保存的唯一路径,因为可能存在名字重复的问题,因此使用该函数确保图片路径唯一。
  225. */
  226. protected function getUniqueImgNameInPath($imgSaveFloder, $name, $imageType, $randStr = '')
  227. {
  228. $imagePath = $imgSaveFloder.'/'.$name.$randStr.'.'.$imageType;
  229. if (!file_exists($imagePath)) {
  230. return $name.$randStr.'.'.$imageType;
  231. } else {
  232. $randStr = time().rand(10000, 99999);
  233. return $this->getUniqueImgNameInPath($imgSaveFloder, $name, $imageType, $randStr);
  234. }
  235. }
  236. }