Bitrix-D7 23.9
 
Загрузка...
Поиск...
Не найдено
sitemapfile.php
1<?php
8namespace Bitrix\Seo;
9
14
21 extends File
22{
23 const XML_HEADER = '<?xml version="1.0" encoding="UTF-8"?>';
24
25 const FILE_HEADER = '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">';
26 const FILE_FOOTER = '</urlset>';
27
28 const ENTRY_TPL = '<url><loc>%s</loc><lastmod>%s</lastmod></url>';
29 const ENTRY_TPL_SEARCH = '<url><loc>%s</loc>';
30
31 const XPATH_URL = '/urlset/url';
32
33 const MAX_SIZE = 5000000;
34
35 const FILE_EXT = '.xml';
36 const FILE_PART_SUFFIX = '.part';
37
38 protected $documentRoot;
39 protected $settings = array();
40 protected $parser = false;
41
42 protected $siteRoot = '';
43 protected $partFile = '';
44 protected $partList = array();
45 protected $part = 0;
46 protected $partChanged = false;
47 protected $footerClosed = false;
48
49 protected $urlToSearch = '';
50 protected $urlFound = false;
51
52 public function __construct($fileName, $settings)
53 {
54 $this->settings = array(
55 'SITE_ID' => $settings['SITE_ID'],
56 'PROTOCOL' => $settings['PROTOCOL'] == 'https' ? 'https' : 'http',
57 'DOMAIN' => $settings['DOMAIN'],
58 );
59
60 $site = SiteTable::getRow(array("filter" => array("LID" => $this->settings['SITE_ID'])));
61
62 $this->documentRoot = SiteTable::getDocumentRoot($this->settings['SITE_ID']);
63 $this->footerClosed = false;
64
65 $this->siteRoot = Path::combine(
66 $this->documentRoot,
67 $site['DIR']
68 );
69
70 $fileName = $this->prepareFileName($fileName);
71 $this->partFile = $this->partFile ?: $fileName;
72 $this->pathPhysical = null; // hack for object reconstuct during file splitting
73 parent::__construct($this->siteRoot.'/'.$fileName, $this->settings['SITE_ID']);
74 $this->partChanged = $this->isExists() && !$this->isSplitNeeded();
75 }
76
77 protected function prepareFileName($fileName)
78 {
79 // normalize slashes
80 $fileName = Path::normalize($fileName);
81 if (mb_substr($fileName, -mb_strlen(self::FILE_EXT)) != self::FILE_EXT)
82 {
83 $fileName .= self::FILE_EXT;
84 }
85
86 // convert words delimiter, google dont't like '_''
87 $fileName = str_replace('_', '-', $fileName);
88
89 return $fileName;
90 }
91
97 protected function reInit($fileName)
98 {
99 $this->__construct($fileName, $this->settings);
100 }
101
107 public function addHeader()
108 {
109 $this->partChanged = true;
110 $this->putContents(self::XML_HEADER.self::FILE_HEADER);
111 }
112
119 protected function isSplitNeeded()
120 {
121 return $this->isExists() && $this->getSize() >= self::MAX_SIZE;
122 }
123
135 public function addEntry($entry)
136 {
137 if ($this->isSplitNeeded())
138 {
139 $this->split();
140 $this->addEntry($entry);
141 }
142 else
143 {
144 if (!$this->partChanged)
145 {
146 $this->addHeader();
147 }
148
149 $this->putContents(
150 sprintf(
151 self::ENTRY_TPL,
152 Converter::getXmlConverter()->encode($entry['XML_LOC']),
153 Converter::getXmlConverter()->encode($entry['XML_LASTMOD'])
154 ), self::APPEND
155 );
156 }
157 }
158
164 public function split()
165 {
166 if($this->partChanged)
167 {
168 $this->addFooter();
169 }
170
171 $this->partList[] = $this->getName();
172 $this->part++;
173
174 $fileName = $this->partFile;
175 $fileName = mb_substr($fileName, 0, -mb_strlen(self::FILE_EXT)).self::FILE_PART_SUFFIX.$this->part.mb_substr($fileName, -mb_strlen(self::FILE_EXT));
176
177 $this->reInit($fileName);
178
179 $this->partChanged = $this->isExists() && !$this->isSplitNeeded();
180
181 return $fileName;
182 }
183
189 public function getNameList()
190 {
191 return $this->isCurrentPartNotEmpty() ? array_merge($this->partList, array($this->getName())) : $this->partList;
192 }
193
198 public function getPathDirectory()
199 {
200// normalize slashes
201 $siteRoot = Path::normalize($this->siteRoot);
202 $fileName = $this->getName();
203 $path = Path::normalize($this->path);
204
205 $directory = str_replace(array($siteRoot, $fileName), array('',''), $path);
206
207 return ltrim($directory, '/');
208 }
209
215 public function isNotEmpty()
216 {
217 return (count($this->partList) > 0) || $this->isCurrentPartNotEmpty();
218 }
219
225 public function isCurrentPartNotEmpty()
226 {
227 if($this->isExists())
228 {
229 $c = $this->getContents();
230 return $c <> '' && $c != self::XML_HEADER.self::FILE_HEADER;
231 }
232
233 return false;
234 }
235
247 public function appendEntry($entry)
248 {
249 if($this->isSplitNeeded())
250 {
251 $this->split();
252 $this->appendEntry($entry);
253 }
254 else
255 {
256 if(!$this->partChanged)
257 {
258 $this->addHeader();
259 $offset = $this->getSize();
260 }
261 else
262 {
263 $offset = $this->getSize() - mb_strlen(self::FILE_FOOTER);
264 }
265
266 $fd = $this->open('r+');
267
268 fseek($fd, $offset);
269 fwrite($fd, sprintf(
270 self::ENTRY_TPL,
271 Converter::getXmlConverter()->encode($entry['XML_LOC']),
272 Converter::getXmlConverter()->encode($entry['XML_LASTMOD'])
273 ).self::FILE_FOOTER);
274 fclose($fd);
275
276 $this->footerClosed = true;
277 }
278 }
279
291 public function removeEntry($url)
292 {
293 $fileName = $this->partFile;
294 $e = [];
295 $url = $this->settings['PROTOCOL'] . '://' . \CBXPunycode::toASCII($this->settings['DOMAIN'], $e) . $url;
296 $pattern = sprintf(self::ENTRY_TPL_SEARCH, $url);
297
298 while($this->isExists())
299 {
300 $c = $this->getContents();
301 $p = mb_strpos($c, $pattern);
302 unset($c);
303
304 if($p !== false)
305 {
306 $fd = $this->open('r+');
307
308 fseek($fd, intval($p));
309 fwrite($fd, str_repeat(" ", mb_strlen(sprintf(
310 self::ENTRY_TPL,
311 Converter::getXmlConverter()->encode($url),
312 Converter::getXmlConverter()->encode(date('c'))
313 ))));
314 fclose($fd);
315 break;
316 }
317
318 if(!$this->isSplitNeeded())
319 {
320 break;
321 }
322 else
323 {
324 $this->part++;
325 $fileName = mb_substr($fileName, 0, -mb_strlen(self::FILE_EXT)).self::FILE_PART_SUFFIX.$this->part.mb_substr($fileName, -mb_strlen(self::FILE_EXT));
326 $this->reInit($fileName);
327 }
328 }
329
330 return $fileName;
331 }
332
341 public function addFileEntry(File $f)
342 {
343 if($f->isExists() && !$f->isSystem())
344 {
345 $e = [];
346 $this->addEntry(array(
347 'XML_LOC' => $this->settings['PROTOCOL'].'://'.\CBXPunycode::toASCII($this->settings['DOMAIN'], $e).$this->getFileUrl($f),
348 'XML_LASTMOD' => date('c', $f->getModificationTime()),
349 ));
350 }
351 }
352
361 public function addIBlockEntry($url, $modifiedDate)
362 {
363 $e = [];
364 $this->addEntry(array(
365 'XML_LOC' => $this->settings['PROTOCOL'].'://'.\CBXPunycode::toASCII($this->settings['DOMAIN'], $e).$url,
366 'XML_LASTMOD' => date('c', $modifiedDate - \CTimeZone::getOffset()),
367 ));
368 }
369
378 public function appendIBlockEntry($url, $modifiedDate)
379 {
380 if($this->isExists())
381 {
382 $e = [];
383 $this->appendEntry(array(
384 'XML_LOC' => $this->settings['PROTOCOL'].'://'.\CBXPunycode::toASCII($this->settings['DOMAIN'], $e).$url,
385 'XML_LASTMOD' => date('c', $modifiedDate - \CTimeZone::getOffset()),
386 ));
387 }
388 else
389 {
390 $this->addHeader();
391 $this->addIBlockEntry($url, $modifiedDate);
392 $this->addFooter();
393 }
394 }
395
401 public function addFooter()
402 {
403 $this->putContents(self::FILE_FOOTER, self::APPEND);
404 $this->footerClosed = true;
405 }
406
412 public function getSiteRoot()
413 {
414 return $this->siteRoot;
415 }
416
422 public function getUrl()
423 {
424 $e = [];
425 return $this->settings['PROTOCOL'].'://'.\CBXPunycode::toASCII($this->settings['DOMAIN'], $e).$this->getFileUrl($this);
426 }
427
434 public function parse()
435 {
436 if(!$this->parser)
437 {
438 if($this->isExists())
439 {
440 $this->parser = new \CDataXML();
441 $this->parser->loadString($this->getContents());
442 }
443 }
444
445 return $this->parser;
446 }
447
455 protected function getFileUrl(File $f)
456 {
457 static $indexNames;
458 if(!is_array($indexNames))
459 {
460 $indexNames = GetDirIndexArray();
461 }
462
463 $documentRoot = Path::normalize($this->documentRoot);
464 $path = '/';
465 if (mb_substr($this->path, 0, mb_strlen($documentRoot)) === $documentRoot)
466 {
467 $path = '/'.mb_substr($f->getPath(), mb_strlen($documentRoot));
468 }
469
470 $path = Path::convertLogicalToUri($path);
471
472 $path = in_array($f->getName(), $indexNames)
473 ? str_replace('/'.$f->getName(), '/', $path)
474 : $path;
475
476 return '/'.ltrim($path, '/');
477 }
478}
putContents($data, $flags=self::REWRITE)
Definition file.php:65
$path
getPath()
getName()
isSystem()
addIBlockEntry($url, $modifiedDate)
appendIBlockEntry($url, $modifiedDate)
__construct($fileName, $settings)