Url.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457
  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 Yii;
  11. /**
  12. * Url Services
  13. *
  14. * @property \fecshop\services\url\Category $category category sub-service of url
  15. * @property \fecshop\services\url\Rewrite $rewrite rewrite sub-service of url
  16. *
  17. * Url Service
  18. * @author Terry Zhao <2358269014@qq.com>
  19. * @since 1.0
  20. */
  21. class Url extends Service
  22. {
  23. public $randomCount = 8;
  24. public $showScriptName;
  25. protected $_secure;
  26. protected $_currentBaseUrl;
  27. protected $_origin_url;
  28. protected $_httpType;
  29. protected $_baseUrl;
  30. protected $_currentUrl;
  31. /**
  32. * About: 对于 \yii\helpers\CUrl 已经 封装了一些对url的操作,也就是基于yii2的url机制进行的
  33. * 但是对于前端并不适用,对于域名当首页http://xx.com这类url是没有问题,但是,
  34. * 对于子目录当首页的时候就会出问题: 譬如:http://xx.com/zh , http://xx.com/es , http://xx.com/fr 这类得有一定目录的url,则不能满足要求
  35. * 另外前端页面为了seo要求,还会加入url自定义等要求,作为Yii2的url,已经不能满足要求,
  36. * 因此这里重新封装,对于前端页面,请使用 Yii::$service->url.
  37. * 对于admin部分,不会涉及到重写url和域名子目录作为htmlUrl的情况,因此admin部分还是可以用\yii\helpers\CUrl的。
  38. */
  39. /**
  40. * save custom url to mongodb collection url_rewrite.
  41. * @param $str|String, example: fashion handbag women
  42. * @param $originUrl|string , origin url ,example: /cms/home/index?id=5
  43. * @param $originUrlKey|String,origin url key, it can be empty ,or generate by system , or custom url key.
  44. * @param $type|String, url rewrite type.
  45. * @return rewrite Key.
  46. */
  47. protected function actionSaveRewriteUrlKeyByStr($str, $originUrl, $originUrlKey, $type = 'system')
  48. {
  49. $str = trim($str);
  50. $originUrl = $originUrl ? '/'.trim($originUrl, '/') : '';
  51. $originUrlKey = $originUrlKey ? '/'.trim($originUrlKey, '/') : '';
  52. if ($originUrlKey) {
  53. /**
  54. * if originUrlKey and originUrl is exist in url rewrite collectons.
  55. */
  56. $model = $this->find();
  57. $data_one = $model->where([
  58. 'custom_url_key' => $originUrlKey,
  59. 'origin_url' => $originUrl,
  60. ])->one();
  61. if (isset($data_one['custom_url_key'])) {
  62. // 只要进行了查询,就要更新一下rewrite url表的updated_at.
  63. $data_one->updated_at = time();
  64. $data_one->save();
  65. return $originUrlKey;
  66. }
  67. }
  68. if ($originUrlKey) {
  69. $urlKey = $this->generateUrlByName($originUrlKey);
  70. } else {
  71. $urlKey = $this->generateUrlByName($str);
  72. }
  73. if (strlen($urlKey) <= 1) {
  74. $urlKey .= $this->getRandom();
  75. }
  76. if (strlen($urlKey) <= 2) {
  77. $urlKey .= '-'.$this->getRandom();
  78. }
  79. $urlKey = $this->getRewriteUrlKey($urlKey, $originUrl);
  80. $UrlRewrite = $this->findOne([
  81. 'origin_url' => $originUrl,
  82. ]);
  83. if (!isset($UrlRewrite['origin_url'])) {
  84. $UrlRewrite = $this->newModel();
  85. $UrlRewrite->created_at = time();
  86. }
  87. $UrlRewrite->updated_at = time();
  88. $UrlRewrite->type = $type;
  89. $UrlRewrite->custom_url_key = $urlKey;
  90. $UrlRewrite->origin_url = $originUrl;
  91. $UrlRewrite->save();
  92. return $urlKey;
  93. }
  94. /**
  95. * @param $url_key|string
  96. * remove url rewrite data by $url_key,which is custom url key that saved in custom url modules,like articcle , product, category ,etc..
  97. */
  98. protected function actionRemoveRewriteUrlKey($url_key)
  99. {
  100. $model = $this->findOne([
  101. 'custom_url_key' => $url_key,
  102. ]);
  103. if ($model['custom_url_key']) {
  104. $model->delete();
  105. }
  106. }
  107. /**
  108. * 得到当前的url,使用的是php的方式,而不是Yii2的函数
  109. * 对于Yii框架得到当前的url使用:\yii\helpers\BaseUrl::current([],true)
  110. * 这里没有使用的原因是,因为fecshop存在url rewrite,在初始化的时候,会将当前的url转换成yii2框架的url
  111. * 当前函数返回的url,是浏览器地址栏中的当前url,而\yii\helpers\BaseUrl::current([],true) 返回的yii2框架中的url
  112. * 这个要分清楚使用
  113. * 譬如分类页面的url,进行了url rewrite:http://fecshop.appfront.fancyecommerce.com/men
  114. * 1.函数`\yii\helpers\BaseUrl::current([],true)`的输出为:http://fecshop.appfront.fancyecommerce.com/catalog/category/index?_id=57b6ac42f656f246653bf576
  115. * 2.而当前函数`getCurrentUrl()`的输出为:http://fecshop.appfront.fancyecommerce.com/men
  116. * 3.关于fecshop url rewrite,详细参看:http://www.fecshop.com/doc/fecshop-guide/instructions/cn-1.0/guide-fecshop_url_rewrite.html
  117. */
  118. public function getCurrentUrl()
  119. {
  120. if (!$this->_currentUrl) {
  121. $secure = Yii::$app->getRequest()->getIsSecureConnection();
  122. $http = $secure ? 'https' : 'http';
  123. $this->_currentUrl = $http . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
  124. }
  125. return $this->_currentUrl;
  126. }
  127. protected function actionGetCurrentUrlNoParam()
  128. {
  129. $currentUrl = $this->getCurrentUrl();
  130. if (strstr($currentUrl, '?')) {
  131. $currentUrl = substr($currentUrl, 0, strpos($currentUrl, '?'));
  132. }
  133. return $currentUrl;
  134. }
  135. /**
  136. * @param $urlKey|string
  137. * get $origin_url by $custom_url_key ,it is used for yii2 init,
  138. * in (new fecshop\services\Request)->resolveRequestUri(), ## fecshop\services\Request is extend yii\web\Request
  139. */
  140. protected function actionGetOriginUrl($urlKey)
  141. {
  142. return Yii::$service->url->rewrite->getOriginUrl($urlKey);
  143. }
  144. /**
  145. * @param $url_key | String urlKey的值
  146. * @param $params | Array 。url里面个各个参数
  147. * @param https | boolean 是否使用https的方式
  148. * @param $domain | String , 相应的域名,譬如www.fecshop.com
  149. * @proeprty $showScriptName | boolean,是否在url中包含index.php/部分
  150. * @param $useHttpForUrl | boolean ,是否在url中加入http部分、
  151. * 通过传入domain的方式得到相应的url
  152. * 该功能一般是在脚本中通过各个域名的传入得到相应的url,譬如sitemap的生成就是应用了这个方法得到
  153. * 产品和分类的url。
  154. */
  155. protected function actionGetUrlByDomain($url_key, $params = [], $https = false, $domain, $showScriptName = false, $useHttpForUrl = false)
  156. {
  157. $first_str = substr($url_key, 0, 1);
  158. if ($first_str == '/') {
  159. $jg = '';
  160. } else {
  161. $jg = '/';
  162. }
  163. if ($useHttpForUrl) {
  164. if ($https) {
  165. $baseUrl = 'https://'.$domain;
  166. } else {
  167. $baseUrl = 'http://'.$domain;
  168. }
  169. } else {
  170. $baseUrl = '//'.$domain;
  171. }
  172. if ($showScriptName) {
  173. $baseUrl .= '/index.php';
  174. }
  175. if (is_array($params) && !empty($params)) {
  176. $arr = [];
  177. foreach ($params as $k => $v) {
  178. $arr[] = $k.'='.$v;
  179. }
  180. return $baseUrl.$jg.$url_key.'?'.implode('&', $arr);
  181. }
  182. return $url_key ? $baseUrl.$jg.$url_key : $baseUrl;
  183. }
  184. /**
  185. * @param $path|String, for example about-us.html, fashion-handbag/women.html
  186. * genarate current store url by path.
  187. * example:
  188. * Yii::$service->url->getUrlByPath('cms/article/index?id=33');
  189. * Yii::$service->url->getUrlByPath('cms/article/index',['id'=>33]);
  190. * Yii::$service->url->getUrlByPath('cms/article/index',['id'=>33],true);
  191. */
  192. protected function actionGetUrl($path, $params = [], $https = false)
  193. {
  194. $first_str = substr($path, 0, 1);
  195. if ($first_str == '/') {
  196. $jg = '';
  197. } else {
  198. $jg = '/';
  199. }
  200. $baseUrl = $this->getBaseUrl();
  201. if (is_array($params) && !empty($params)) {
  202. $arr = [];
  203. foreach ($params as $k => $v) {
  204. $arr[] = $k.'='.$v;
  205. }
  206. return $baseUrl.$jg.$path.'?'.implode('&', $arr);
  207. }
  208. return $baseUrl.$jg.$path;
  209. }
  210. /**
  211. * get current base url , is was generate by http(or https ).'://'.store_code.
  212. */
  213. protected function actionGetCurrentBaseUrl()
  214. {
  215. if (!$this->_currentBaseUrl) {
  216. $homeUrl = $this->homeUrl();
  217. if ($this->showScriptName) {
  218. $homeUrl .= '/index.php';
  219. }
  220. $this->_currentBaseUrl = $homeUrl;
  221. //if(!$this->_httpType)
  222. // $this->_httpType = $this->secure() ? 'https' : 'http';
  223. //$this->_currentBaseUrl = str_replace("http",$this->_httpType,$homeUrl);
  224. }
  225. return $this->_currentBaseUrl;
  226. }
  227. /**
  228. * get current home url , is was generate by 'http://'.store_code.
  229. */
  230. public function homeUrl()
  231. {
  232. return Yii::$app->getHomeUrl();
  233. }
  234. /**
  235. * get base url.
  236. */
  237. protected function getBaseUrl()
  238. {
  239. if (!$this->_baseUrl) {
  240. $this->_baseUrl = $this->homeUrl();
  241. if ($this->showScriptName) {
  242. $this->_baseUrl .= '/index.php';
  243. }
  244. }
  245. return $this->_baseUrl;
  246. }
  247. protected function newModel()
  248. {
  249. return Yii::$service->url->rewrite->newModel();
  250. }
  251. protected function find()
  252. {
  253. return Yii::$service->url->rewrite->find();
  254. }
  255. protected function findOne($where)
  256. {
  257. return Yii::$service->url->rewrite->findOne($where);
  258. }
  259. /**
  260. * check current url type is http or https. https is secure url type.
  261. */
  262. /*
  263. protected function secure(){
  264. if($this->_secure === null){
  265. if($_SERVER['SERVER_PORT'] == 443){
  266. $this->_secure = true;
  267. }else{
  268. $this->_secure = false;
  269. }
  270. }
  271. return $this->_secure;
  272. }
  273. */
  274. /**
  275. * get rewrite url key.
  276. */
  277. protected function getRewriteUrlKey($urlKey, $originUrl)
  278. {
  279. $model = $this->find();
  280. $data = $model->where([
  281. 'custom_url_key' => $urlKey,
  282. ])->andWhere(['<>', 'origin_url', $originUrl])
  283. ->asArray()->one();
  284. if (isset($data['custom_url_key'])) {
  285. $urlKey = $this->getRandomUrlKey($urlKey);
  286. return $this->getRewriteUrlKey($urlKey, $originUrl);
  287. } else {
  288. return $urlKey;
  289. }
  290. }
  291. /**
  292. * generate random string.
  293. */
  294. protected function getRandom($length = '')
  295. {
  296. if (!$length) {
  297. $length = $this->randomCount;
  298. }
  299. $str = null;
  300. $strPol = '123456789';
  301. $max = strlen($strPol) - 1;
  302. for ($i = 0; $i < $length; $i++) {
  303. $str .= $strPol[rand(0, $max)]; //rand($min,$max)生成介于min和max两个数之间的一个随机整数
  304. }
  305. return $str;
  306. }
  307. /**
  308. * if url key is exist in url_rewrite table ,Behind url add some random string.
  309. */
  310. protected function getRandomUrlKey($url)
  311. {
  312. if ($this->_origin_url) {
  313. $suffix = '';
  314. $o_url = $this->_origin_url;
  315. if (strstr($this->_origin_url, '.')) {
  316. list($o_url, $suffix) = explode('.', $this->_origin_url);
  317. $randomStr = $this->getRandom();
  318. return $o_url.'-'.$randomStr.'.'.$suffix;
  319. }
  320. $randomStr = $this->getRandom();
  321. return $this->_origin_url.'-'.$randomStr;
  322. }
  323. }
  324. /**
  325. * clear character that can not use for url.
  326. */
  327. protected function generateUrlByName($name)
  328. {
  329. setlocale(LC_ALL, '');
  330. $url = iconv('UTF-8', 'ASCII//TRANSLIT', $name);
  331. $url = preg_replace('{[^a-zA-Z0-9_.| -]}', '', $url);
  332. $url = strtolower(trim($url, '-'));
  333. $url = preg_replace('{[_| -]+}', '-', $url);
  334. $url = '/'.trim($url, '/');
  335. $this->_origin_url = $url;
  336. return $url;
  337. }
  338. /**
  339. * @param $url|string 要处理的url , 一般是当前的url
  340. * @param $removeUrlParamStr|string 在url中删除的部分,一般是某个key对应的某个val,譬如color=green
  341. * @param $backToPage1|bool 删除后,页数由原来的页数变成第一页?
  342. */
  343. protected function actionRemoveUrlParamVal($url, $removeUrlParamStr, $backToPage1 = true)
  344. {
  345. $return_url = $url;
  346. if (strstr($url, '?'.$removeUrlParamStr.'&')) {
  347. $return_url = str_replace('?'.$removeUrlParamStr.'&', '?', $url);
  348. } elseif (strstr($url, '?'.$removeUrlParamStr)) {
  349. $return_url = str_replace('?'.$removeUrlParamStr, '', $url);
  350. } elseif (strstr($url, '&'.$removeUrlParamStr)) {
  351. $return_url = str_replace('&'.$removeUrlParamStr, '', $url);
  352. }
  353. if ($backToPage1) {
  354. $pVal = Yii::$app->request->get('p');
  355. if ($pVal) {
  356. $originPUrl = 'p='.$pVal;
  357. $afterPUrl = 'p=1';
  358. }
  359. if ($originPUrl) {
  360. $return_url = str_replace($originPUrl, $afterPUrl, $return_url);
  361. }
  362. }
  363. return $return_url;
  364. }
  365. /**
  366. * url 跳转.
  367. */
  368. protected function actionRedirect($url)
  369. {
  370. if ($url) {
  371. //session_commit();
  372. Yii::$app->getResponse()->redirect($url)->send();
  373. //header("Location: $url");
  374. }
  375. }
  376. protected function actionRedirectByUrlKey($urlKey, $params = [])
  377. {
  378. if ($urlKey) {
  379. $url = $this->getUrl($urlKey, $params);
  380. //session_commit();
  381. Yii::$app->getResponse()->redirect($url)->send();
  382. //header("Location: $url");
  383. }
  384. }
  385. protected function actionRedirectHome()
  386. {
  387. $homeUrl = $this->HomeUrl();
  388. if ($homeUrl) {
  389. Yii::$app->getResponse()->redirect($homeUrl)->send();
  390. //session_commit();
  391. //header("Location: $homeUrl");
  392. }
  393. }
  394. protected function actionRedirect404()
  395. {
  396. $error404UrlKey = Yii::$app->errorHandler->errorAction;
  397. $error404Url = $this->getUrl($error404UrlKey);
  398. if ($error404Url) {
  399. Yii::$app->getResponse()->redirect($error404Url)->send();
  400. }
  401. }
  402. }