DefaultController.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271
  1. <?php
  2. namespace sitemap\controllers;
  3. use Yii;
  4. use yii\web\Controller;
  5. use yii\web\Response;
  6. use yii\helpers\ArrayHelper;
  7. use yii\helpers\Url;
  8. use DOMDocument;
  9. use app\models\front\News;
  10. use yii\db\ActiveQuery;
  11. use yii\db\Query;
  12. use yii\db\Expression;
  13. /**
  14. * DefaultController implements actions
  15. */
  16. class DefaultController extends Controller
  17. {
  18. const ALWAYS = 'always';
  19. const HOURLY = 'hourly';
  20. const DAILY = 'daily';
  21. const WEEKLY = 'weekly';
  22. const MONTHLY = 'monthly';
  23. const YEARLY = 'yearly';
  24. const NEVER = 'never';
  25. const ITEMSONPAGE = 200;
  26. protected $items = array();
  27. public $defaultAction = 'index';
  28. public function actions()
  29. {
  30. return [
  31. 'error' => [
  32. 'class' => 'yii\web\ErrorAction',
  33. ],
  34. ];
  35. }
  36. public function actionIndex()
  37. {
  38. $activenews = Yii::$app->cache->getOrSet("active-news",function (){
  39. $query = new Query;
  40. $query->select('count(`id`) as cnt')
  41. ->from(News::tableName())
  42. ->where(['active'=>'Y'])
  43. ->andWhere(["<=","dt_pub",date("Y-m-d H:i:00")])
  44. ->limit(1);
  45. $rows = $query->one();
  46. return $rows['cnt'];
  47. },60*60*2);
  48. Yii::$app->cache->set('active-news-cnt', $activenews);
  49. $items = [];
  50. $count = round($activenews/self::ITEMSONPAGE)-1;
  51. for ($i = 0; $i <= $count; $i++){
  52. $items[] = ['loc'=>'https://www.amic.ru/sitemap/news/'.$i];
  53. }
  54. $content = $this->GetIndexXML($items);
  55. Yii::$app->response->format = \yii\web\Response::FORMAT_RAW;
  56. Yii::$app->response->headers->set('content-type', 'application/xml;charset=utf-8');
  57. return $this->renderPartial('/main',['content' => $content]);
  58. }
  59. public function actionNews($page)
  60. {
  61. $activenews = Yii::$app->cache->get('active-news-cnt' );
  62. if( !$activenews ){
  63. $activenews = Yii::$app->cache->getOrSet("active-news",function (){
  64. $query = new Query;
  65. $query->select('count(`id`) as cnt')
  66. ->from(News::tableName())
  67. ->where(['active'=>'Y'])
  68. ->andWhere(["<=","dt_pub",date("Y-m-d H:i:00")])
  69. ->limit(1);
  70. $rows = $query->one();
  71. return $rows['cnt'];
  72. },60*60*2);
  73. }
  74. $max_page = round($activenews/self::ITEMSONPAGE) - 1;
  75. $invert_page = $max_page - $page;
  76. if( $page > $max_page ) return '';
  77. $yandex = ( strpos( $_SERVER['HTTP_USER_AGENT'], 'andex' ) === false )?'':'_y';
  78. $cache = Yii::$app->cache;
  79. $key = "sitemap-a_{$page}{$yandex}";
  80. if( isset($_REQUEST['purge']) && $_REQUEST['purge'] == 'PURGE' ){
  81. $cache->delete($key);
  82. }
  83. $data = $cache->get($key);
  84. $ctime = 60*60*24*180+rand(0,400000);
  85. $scaninterval = self::MONTHLY;
  86. $scanpror = 0.5;
  87. if( $invert_page < 10 ){
  88. $ctime = 60*10;
  89. $scaninterval = self::DAILY;
  90. $scanpror = 0.8;
  91. }
  92. if( $invert_page < 2 ){
  93. $ctime = 60*5;
  94. $scaninterval = self::HOURLY;
  95. $scanpror = 0.9;
  96. }
  97. if ($data === false) {
  98. $crequest = Yii::$app->memcache->get('sitemap_r_cnt');
  99. if( $crequest > 4 ) {
  100. header("HTTP/1.1 429 Too Many Requests");
  101. Yii::$app->end();
  102. return '';
  103. }
  104. Yii::$app->memcache->set('sitemap_r_cnt', $crequest++, 60);
  105. $newsDataProvider = new \yii\data\ActiveDataProvider(
  106. [
  107. "query"=>\app\models\front\News::find()
  108. ->select( 'news.*' )
  109. ->from(new Expression("news FORCE INDEX (top,calendar)"))
  110. ->andwhere(['active'=>'Y'])->orderBy(["id"=>SORT_DESC]),
  111. "pagination" =>[
  112. "pageSize"=>200,
  113. "page"=>$invert_page
  114. ],
  115. ]
  116. );
  117. $this->addModels( $newsDataProvider->getModels(), $scaninterval, $scanpror );
  118. $content = $this->GetXML($invert_page);
  119. $data = $this->renderPartial('/news',['content' => $content]);
  120. $cache->set($key, $data, $ctime);
  121. $crequest = Yii::$app->memcache->get('sitemap_r_cnt');
  122. if( $crequest > 0 ) {
  123. Yii::$app->memcache->set('sitemap_r_cnt', $crequest--, 60);
  124. }
  125. }else{
  126. Yii::$app->response->format = \yii\web\Response::FORMAT_RAW;
  127. Yii::$app->response->headers->set('content-type', 'application/xml;charset=utf-8');
  128. }
  129. return $data;
  130. }
  131. /**
  132. * @return string XML code
  133. */
  134. public function GetIndexXML($items)
  135. {
  136. $dom = new DOMDocument('1.0', 'UTF-8');
  137. $urlset = $dom->createElement('sitemapindex');
  138. $urlset->setAttribute('xmlns','http://www.sitemaps.org/schemas/sitemap/0.9');
  139. foreach($items as $item)
  140. {
  141. $url = $dom->createElement('sitemap');
  142. foreach ($item as $key=>$value)
  143. {
  144. $elem = $dom->createElement($key);
  145. $elem->appendChild($dom->createTextNode($value));
  146. $url->appendChild($elem);
  147. }
  148. $urlset->appendChild($url);
  149. }
  150. $dom->appendChild($urlset);
  151. return $dom->saveXML();
  152. }
  153. /**
  154. * @return string XML code
  155. */
  156. public function GetXML($page)
  157. {
  158. $dom = new DOMDocument('1.0', 'UTF-8');
  159. $urlset = $dom->createElement('urlset');
  160. $urlset->setAttribute('xmlns:xsi','https://www.w3.org/2001/XMLSchema-instance');
  161. $urlset->setAttribute('xmlns','https://www.sitemaps.org/schemas/sitemap/0.9');
  162. $urlset->setAttribute('xsi:schemaLocation',"https://www.sitemaps.org/schemas/sitemap/0.9 https://www.sitemaps.org/schemas/sitemap/0.9/sitemap.xsd");
  163. $urlset->setAttribute('xmlns:image',"https://www.google.com/schemas/sitemap-image/1.1");
  164. $urlset->setAttribute('xmlns:news',"https://www.google.com/schemas/sitemap-news/0.9");
  165. foreach($this->items as $item)
  166. {
  167. $url = $dom->createElement('url');
  168. $url = $this->recarray($item, $dom, $url);
  169. $urlset->appendChild($url);
  170. }
  171. $dom->appendChild($urlset);
  172. return $dom->saveXML();
  173. }
  174. protected function recarray($array, $dom, $url)
  175. {
  176. foreach($array as $key=>$value)
  177. {
  178. $elem = $dom->createElement($key);
  179. if(is_array($value))
  180. {
  181. $urle = $this->recarray($value, $dom, $elem);
  182. $url->appendChild($urle);
  183. }else{
  184. $elem->appendChild($dom->createTextNode($value));
  185. $url->appendChild($elem);
  186. }
  187. }
  188. return $url;
  189. }
  190. protected function dateToW3C($date)
  191. {
  192. if (is_int($date))
  193. return date(DATE_W3C, $date);
  194. else
  195. return date(DATE_W3C, strtotime($date));
  196. }
  197. /**
  198. * @param CActiveRecord[] $models
  199. * @param string $changeFreq
  200. * @param float $priority
  201. */
  202. public function addModels($models, $changeFreq=self::DAILY, $priority=0.5)
  203. {
  204. $host = Yii::$app->request->hostInfo;
  205. $host = 'https://www.amic.ru';
  206. $yandex = ( strpos( $_SERVER['HTTP_USER_AGENT'], 'andex' ) === false )?false:true;
  207. foreach ($models as $model)
  208. {
  209. $item = [
  210. 'loc' => $host.$model->GetUrl(),
  211. 'changefreq' => $changeFreq,
  212. 'priority' => $priority
  213. ];
  214. if ($model->hasAttribute('dt_upd') && $model->dt_upd)
  215. {
  216. $item['lastmod'] = $this->dateToW3C($model->dt_upd);
  217. }else{
  218. $item['lastmod'] = $this->dateToW3C($model->dt_pub);
  219. }
  220. if( !$yandex ){
  221. $item['image:image'] = [
  222. 'image:loc' => $model->getImage('jpg')->getUrl(),
  223. 'image:caption' => ( $model->photo_title == '' )?$model->title:$model->photo_title //get_imageTitle
  224. ];
  225. $item['news:news'] =[
  226. 'news:publication_date' => $model->dt_pub,
  227. 'news:title' => $model->title,
  228. 'news:publication' =>
  229. [
  230. 'news:name' => 'amic.ru',
  231. 'news:language' => 'ru'
  232. ]
  233. ];
  234. }
  235. $this->items[] = $item;
  236. }
  237. }
  238. public function addUrl($url, $changeFreq=self::DAILY, $priority=0.5, $lastMod=0)
  239. {
  240. $host = Yii::$app->request->hostInfo;
  241. $host = 'https://www.amic.ru';
  242. $item = array(
  243. 'loc' => $host . $url,
  244. 'changefreq' => $changeFreq,
  245. 'priority' => $priority
  246. );
  247. if ($lastMod)
  248. $item['lastmod'] = $this->dateToW3C($lastMod);
  249. $this->items[] = $item;
  250. }
  251. }