Url.php 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538
  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 = 9;
  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 && $originUrl) {
  53. /**
  54. * if originUrlKey and originUrl is exist in url rewrite collectons.
  55. */
  56. $model = $this->find();
  57. // 如果已经存在,那么直接返回
  58. $data_one = $model->where([
  59. 'custom_url_key' => $originUrlKey,
  60. 'origin_url' => $originUrl,
  61. ])->one();
  62. if (isset($data_one['custom_url_key'])) {
  63. return $originUrlKey;
  64. }
  65. /*
  66. $data_one = $model->where([
  67. 'custom_url_key' => $originUrlKey,
  68. 'origin_url' => $originUrl,
  69. ])->one();
  70. if (isset($data_one['custom_url_key'])) {
  71. // 只要进行了查询,就要更新一下rewrite url表的updated_at.
  72. $data_one->updated_at = time();
  73. $data_one->origin_url = $originUrl;
  74. $data_one->save();
  75. return $originUrlKey;
  76. }
  77. */
  78. }
  79. if ($originUrlKey) {
  80. $urlKey = $this->generateUrlByName($originUrlKey);
  81. } else {
  82. $urlKey = $this->generateUrlByName($str);
  83. }
  84. if (strlen($urlKey) <= 1) {
  85. $urlKey .= $this->getRandom();
  86. }
  87. if (strlen($urlKey) <= 2) {
  88. $urlKey .= '-'.$this->getRandom();
  89. }
  90. $urlKey = $this->getRewriteUrlKey($urlKey, $originUrl);
  91. $UrlRewrite = $this->findOne([
  92. 'origin_url' => $originUrl,
  93. ]);
  94. if (!isset($UrlRewrite['origin_url'])) {
  95. $UrlRewrite = $this->newModel();
  96. $UrlRewrite->created_at = time();
  97. }
  98. $UrlRewrite->updated_at = time();
  99. $UrlRewrite->type = $type;
  100. $UrlRewrite->custom_url_key = $urlKey;
  101. $UrlRewrite->origin_url = $originUrl;
  102. $UrlRewrite->save();
  103. return $urlKey;
  104. }
  105. /**
  106. * @param $url_key|string
  107. * remove url rewrite data by $url_key,which is custom url key that saved in custom url modules,like articcle , product, category ,etc..
  108. */
  109. protected function actionRemoveRewriteUrlKey($url_key)
  110. {
  111. $model = $this->findOne([
  112. 'custom_url_key' => $url_key,
  113. ]);
  114. if ($model['custom_url_key']) {
  115. $model->delete();
  116. }
  117. }
  118. /**
  119. * 得到当前的url,使用的是php的方式,而不是Yii2的函数
  120. * 对于Yii框架得到当前的url使用:\yii\helpers\BaseUrl::current([],true)
  121. * 这里没有使用的原因是,因为fecshop存在url rewrite,在初始化的时候,会将当前的url转换成yii2框架的url
  122. * 当前函数返回的url,是浏览器地址栏中的当前url,而\yii\helpers\BaseUrl::current([],true) 返回的yii2框架中的url
  123. * 这个要分清楚使用
  124. * 譬如分类页面的url,进行了url rewrite:http://fecshop.appfront.fancyecommerce.com/men
  125. * 1.函数`\yii\helpers\BaseUrl::current([],true)`的输出为:http://fecshop.appfront.fancyecommerce.com/catalog/category/index?_id=57b6ac42f656f246653bf576
  126. * 2.而当前函数`getCurrentUrl()`的输出为:http://fecshop.appfront.fancyecommerce.com/men
  127. * 3.关于fecshop url rewrite,详细参看:http://www.fecshop.com/doc/fecshop-guide/instructions/cn-1.0/guide-fecshop_url_rewrite.html
  128. */
  129. public function getCurrentUrl()
  130. {
  131. if (!$this->_currentUrl) {
  132. $secure = Yii::$app->getRequest()->getIsSecureConnection();
  133. $http = $secure ? 'https' : 'http';
  134. $this->_currentUrl = $http . "://$_SERVER[HTTP_HOST]$_SERVER[REQUEST_URI]";
  135. }
  136. return $this->_currentUrl;
  137. }
  138. protected function actionGetCurrentUrlNoParam()
  139. {
  140. $currentUrl = $this->getCurrentUrl();
  141. if (strstr($currentUrl, '?')) {
  142. $currentUrl = substr($currentUrl, 0, strpos($currentUrl, '?'));
  143. }
  144. return $currentUrl;
  145. }
  146. /**
  147. * @param $urlKey|string
  148. * get $origin_url by $custom_url_key ,it is used for yii2 init,
  149. * in (new fecshop\services\Request)->resolveRequestUri(), ## fecshop\services\Request is extend yii\web\Request
  150. */
  151. protected function actionGetOriginUrl($urlKey)
  152. {
  153. return Yii::$service->url->rewrite->getOriginUrl($urlKey);
  154. }
  155. /**
  156. * @param $url_key | String urlKey的值
  157. * @param $params | Array 。url里面个各个参数
  158. * @param https | boolean 是否使用https的方式
  159. * @param $domain | String , 相应的域名,譬如www.fecshop.com
  160. * @proeprty $showScriptName | boolean,是否在url中包含index.php/部分
  161. * @param $useHttpForUrl | boolean ,是否在url中加入http部分、
  162. * 通过传入domain的方式得到相应的url
  163. * 该功能一般是在脚本中通过各个域名的传入得到相应的url,譬如sitemap的生成就是应用了这个方法得到
  164. * 产品和分类的url。
  165. */
  166. protected function actionGetUrlByDomain($url_key, $params = [], $https = false, $domain, $showScriptName = false, $useHttpForUrl = false)
  167. {
  168. $first_str = substr($url_key, 0, 1);
  169. if ($first_str == '/') {
  170. $jg = '';
  171. } else {
  172. $jg = '/';
  173. }
  174. if ($useHttpForUrl) {
  175. if ($https) {
  176. $baseUrl = 'https://'.$domain;
  177. } else {
  178. $baseUrl = 'http://'.$domain;
  179. }
  180. } else {
  181. $baseUrl = '//'.$domain;
  182. }
  183. if ($showScriptName) {
  184. $baseUrl .= '/index.php';
  185. }
  186. if (is_array($params) && !empty($params)) {
  187. $arr = [];
  188. foreach ($params as $k => $v) {
  189. $arr[] = $k.'='.$v;
  190. }
  191. return $baseUrl.$jg.$url_key.'?'.implode('&', $arr);
  192. }
  193. return $url_key ? $baseUrl.$jg.$url_key : $baseUrl;
  194. }
  195. /**
  196. * @param $path|String, for example about-us.html, fashion-handbag/women.html
  197. * genarate current store url by path.
  198. * example:
  199. * Yii::$service->url->getUrlByPath('cms/article/index?id=33');
  200. * Yii::$service->url->getUrlByPath('cms/article/index',['id'=>33]);
  201. * Yii::$service->url->getUrlByPath('cms/article/index',['id'=>33],true);
  202. */
  203. protected function actionGetUrl($path, $params = [], $https = false)
  204. {
  205. $first_str = substr($path, 0, 1);
  206. if ($first_str == '/') {
  207. $jg = '';
  208. } else {
  209. $jg = '/';
  210. }
  211. $baseUrl = $this->getBaseUrl();
  212. if (is_array($params) && !empty($params)) {
  213. $arr = [];
  214. foreach ($params as $k => $v) {
  215. $arr[] = $k.'='.$v;
  216. }
  217. return $baseUrl.$jg.$path.'?'.implode('&', $arr);
  218. }
  219. return $baseUrl.$jg.$path;
  220. }
  221. /**
  222. * get current base url , is was generate by http(or https ).'://'.store_code.
  223. */
  224. protected function actionGetCurrentBaseUrl()
  225. {
  226. if (!$this->_currentBaseUrl) {
  227. $homeUrl = $this->homeUrl();
  228. if ($this->showScriptName) {
  229. $homeUrl .= '/index.php';
  230. }
  231. $this->_currentBaseUrl = $homeUrl;
  232. //if(!$this->_httpType)
  233. // $this->_httpType = $this->secure() ? 'https' : 'http';
  234. //$this->_currentBaseUrl = str_replace("http",$this->_httpType,$homeUrl);
  235. }
  236. return $this->_currentBaseUrl;
  237. }
  238. /**
  239. * get current home url , is was generate by 'http://'.store_code.
  240. */
  241. public function homeUrl()
  242. {
  243. return Yii::$app->getHomeUrl();
  244. }
  245. /**
  246. * get base url.
  247. */
  248. protected function getBaseUrl()
  249. {
  250. if (!$this->_baseUrl) {
  251. $this->_baseUrl = $this->homeUrl();
  252. if ($this->showScriptName) {
  253. $this->_baseUrl .= '/index.php';
  254. }
  255. }
  256. return $this->_baseUrl;
  257. }
  258. protected function newModel()
  259. {
  260. return Yii::$service->url->rewrite->newModel();
  261. }
  262. protected function find()
  263. {
  264. return Yii::$service->url->rewrite->find();
  265. }
  266. protected function findOne($where)
  267. {
  268. return Yii::$service->url->rewrite->findOne($where);
  269. }
  270. /**
  271. * check current url type is http or https. https is secure url type.
  272. */
  273. /*
  274. protected function secure(){
  275. if($this->_secure === null){
  276. if($_SERVER['SERVER_PORT'] == 443){
  277. $this->_secure = true;
  278. }else{
  279. $this->_secure = false;
  280. }
  281. }
  282. return $this->_secure;
  283. }
  284. */
  285. /**
  286. * get rewrite url key.
  287. */
  288. protected function getRewriteUrlKey($urlKey, $originUrl)
  289. {
  290. $model = $this->find();
  291. $data = $model->where([
  292. 'custom_url_key' => $urlKey,
  293. ])->andWhere(['<>', 'origin_url', $originUrl])
  294. ->asArray()->one();
  295. if (isset($data['custom_url_key'])) {
  296. $urlKey = $this->getRandomUrlKey($urlKey);
  297. return $this->getRewriteUrlKey($urlKey, $originUrl);
  298. } else {
  299. return $urlKey;
  300. }
  301. }
  302. /**
  303. * generate random string.
  304. */
  305. protected function getRandom($length = '')
  306. {
  307. if (!$length) {
  308. $length = $this->randomCount;
  309. }
  310. $str = null;
  311. $strPol = '123456789';
  312. $max = strlen($strPol) - 1;
  313. for ($i = 0; $i < $length; $i++) {
  314. $str .= $strPol[rand(0, $max)]; //rand($min,$max)生成介于min和max两个数之间的一个随机整数
  315. }
  316. return $str;
  317. }
  318. protected function isRandomStr($randomStr)
  319. {
  320. $f = substr($randomStr, 0, 1);
  321. if ($f !== '-') {
  322. return false;
  323. }
  324. $s = substr($randomStr, 1);
  325. if (strlen($s) != $this->randomCount) {
  326. return false;
  327. }
  328. if(!is_numeric($s)){
  329. return false;
  330. }
  331. return true;
  332. }
  333. /**
  334. * if url key is exist in url_rewrite table ,Behind url add some random string.
  335. */
  336. protected function getRandomUrlKey($url)
  337. {
  338. if ($this->_origin_url) {
  339. $suffix = '';
  340. $o_url = $this->_origin_url;
  341. if (strstr($this->_origin_url, '.')) {
  342. list($o_url, $suffix) = explode('.', $this->_origin_url);
  343. $l = $this->randomCount +1;
  344. if (strlen($o_url) > $l) {
  345. $randomStrSub = substr($o_url, strlen($o_url) - $l , $l );
  346. $orignUrlK = substr($o_url, 0, strlen($o_url) - $l );
  347. if ($this->isRandomStr($randomStrSub)) {
  348. $o_url = $orignUrlK;
  349. }
  350. }
  351. $randomStr = $this->getRandom();
  352. return $o_url.'-'.$randomStr.'.'.$suffix;
  353. } else {
  354. $l = $this->randomCount +1;
  355. if (strlen($o_url) > $l) {
  356. $randomStr = substr($o_url, strlen($o_url) - $l , $l );
  357. $orignUrlK = substr($o_url, 0, strlen($o_url) - $l );
  358. if ($this->isRandomStr($randomStr)) {
  359. $o_url = $orignUrlK;
  360. }
  361. }
  362. $randomStr = $this->getRandom();
  363. return $o_url.'-'.$randomStr;
  364. }
  365. }
  366. }
  367. /**
  368. * clear character that can not use for url.
  369. */
  370. protected function generateUrlByName($name)
  371. {
  372. setlocale(LC_ALL, '');
  373. $url = iconv('UTF-8', 'ASCII//TRANSLIT', $name);
  374. $url = preg_replace('{[^a-zA-Z0-9_.| -]}', '', $url);
  375. $url = strtolower(trim($url, '-'));
  376. $url = preg_replace('{[_| -]+}', '-', $url);
  377. $url = '/'.trim($url, '/');
  378. $this->_origin_url = $url;
  379. return $url;
  380. }
  381. /**
  382. * @param $url|string 要处理的url , 一般是当前的url
  383. * @param $removeUrlParamStr|string 在url中删除的部分,一般是某个key对应的某个val,譬如color=green
  384. * @param $backToPage1|bool 删除后,页数由原来的页数变成第一页?
  385. */
  386. protected function actionRemoveUrlParamVal($url, $removeUrlParamStr, $backToPage1 = true)
  387. {
  388. $return_url = $url;
  389. if (strstr($url, '?'.$removeUrlParamStr.'&')) {
  390. $return_url = str_replace('?'.$removeUrlParamStr.'&', '?', $url);
  391. } elseif (strstr($url, '?'.$removeUrlParamStr)) {
  392. $return_url = str_replace('?'.$removeUrlParamStr, '', $url);
  393. } elseif (strstr($url, '&'.$removeUrlParamStr)) {
  394. $return_url = str_replace('&'.$removeUrlParamStr, '', $url);
  395. }
  396. if ($backToPage1) {
  397. $pVal = Yii::$app->request->get('p');
  398. if ($pVal) {
  399. $originPUrl = 'p='.$pVal;
  400. $afterPUrl = 'p=1';
  401. }
  402. if ($originPUrl) {
  403. $return_url = str_replace($originPUrl, $afterPUrl, $return_url);
  404. }
  405. }
  406. return $return_url;
  407. }
  408. /**
  409. * url 跳转.
  410. */
  411. protected function actionRedirect($url)
  412. {
  413. if ($url) {
  414. //session_commit();
  415. Yii::$app->getResponse()->redirect($url)->send();
  416. //header("Location: $url");
  417. }
  418. }
  419. protected function actionRedirectByUrlKey($urlKey, $params = [])
  420. {
  421. if ($urlKey) {
  422. $url = $this->getUrl($urlKey, $params);
  423. //session_commit();
  424. Yii::$app->getResponse()->redirect($url)->send();
  425. //header("Location: $url");
  426. }
  427. }
  428. protected function actionRedirectHome()
  429. {
  430. $homeUrl = $this->HomeUrl();
  431. if ($homeUrl) {
  432. Yii::$app->getResponse()->redirect($homeUrl)->send();
  433. //session_commit();
  434. //header("Location: $homeUrl");
  435. }
  436. }
  437. protected function actionRedirect404()
  438. {
  439. $error404UrlKey = Yii::$app->errorHandler->errorAction;
  440. $error404Url = $this->getUrl($error404UrlKey);
  441. if ($error404Url) {
  442. Yii::$app->getResponse()->redirect($error404Url)->send();
  443. }
  444. }
  445. // 判断是否是首页
  446. public function isHomePage()
  447. {
  448. $rules = Yii::$app->urlManager->rules;
  449. $route = '';
  450. if (!is_array($rules)) {
  451. return false;
  452. }
  453. foreach ($rules as $one) {
  454. $name = $one->name;
  455. if ($name === '') {
  456. $route = $one->route;
  457. }
  458. }
  459. if (!$route) {
  460. return false;
  461. }
  462. // $route 默认为 cms/home/index
  463. $arr = explode('/', $route);
  464. if (count($arr) != 3) {
  465. return false;
  466. }
  467. $mId = Yii::$app->controller->module->id;
  468. $cId = Yii::$app->controller->id;
  469. $aId = Yii::$app->controller->action->id;
  470. // 通过module controler action 的id 与 $routeArr核对,不一致则为false
  471. if ($mId != $arr[0] || $cId != $arr[1] || $aId != $arr[2]) {
  472. return false;
  473. }
  474. return true;
  475. }
  476. }